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 test_trotterize_noisy(self): # Noisy simulations simulation = adiabatic_simulation(line_graph(2), IS_subspace=False, noisy=True, trotterize=True) res_trotterize = simulation.performance_vs_total_time( np.arange(1, 4, 1) * 10, metric='optimum_overlap', schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='trotterize') simulation = adiabatic_simulation(line_graph(2), IS_subspace=False, noisy=True, trotterize=False) res_odeint = simulation.performance_vs_total_time( np.arange(1, 4, 1) * 10, metric='optimum_overlap', schedule=lambda t, tf: simulation.linear_schedule( t, tf, coefficients=[10, 10]), plot=False, verbose=True, method='odeint') self.assertTrue( np.allclose(res_trotterize[0]['trotterize']['optimum_overlap'], res_odeint[0]['odeint']['optimum_overlap'], atol=1e-2))
def plot_schedule(): laser = EffectiveOperatorHamiltonian(graph=line_graph(1), IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=line_graph(1), energies=(2.5, ), index=0) def schedule_exp_fixed_true_bright(t, tf): k = 50 a = .95 b = 3.1 x = t / tf max_omega_g = 1 / np.sqrt(2) max_omega_r = 1 / np.sqrt(2) amplitude = max_omega_g * max_omega_r * ( -1 / (1 + np.e ** (k * (x - a))) ** b - 1 / (1 + np.e ** (-k * (x - (tf - a)))) ** b + 1) / \ (-1 / ((1 + np.e ** (k * (1 / 2 - a))) ** b) - 1 / ( (1 + np.e ** (-k * (1 / 2 - (tf - a)))) ** b) + 1) # Now we need to figure out what the driver strengths should be for STIRAP ratio = max_omega_g / max_omega_r omega_g = np.sqrt(amplitude * ratio) omega_r = np.sqrt(amplitude / ratio) laser.omega_g = omega_g laser.omega_r = omega_r offset = -3 * 2 * (1 / 2 - t / tf) energy_shift.energies = (offset, ) schedule = schedule_exp_fixed_true_bright num = 1000 omega_gs = np.zeros(num) omega_rs = np.zeros(num) energy_shifts = np.zeros(num) i = 0 times = np.linspace(0, 1, num) for t in times: schedule(t, 1) omega_gs[i] = laser.energies[0] * laser.omega_g omega_rs[i] = laser.energies[0] * laser.omega_r energy_shifts[i] = energy_shift.energies[0] i += 1 plt.plot(times, omega_gs, label=r'$\Omega_g$') plt.plot(times, omega_rs, label=r'$\Omega_r$') plt.plot(times, energy_shifts, label=r'$\delta_r$') plt.legend() plt.show()
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 p_check_compare(tau, eps, L=12, h=1, verbose=False): if verbose: print('starting ham') disorder = (np.random.random(size=L) - 1 / 2) * h #disorder = np.array([0.848539, -0.038314, -0.170679, 0.384688, 0.00254869, 0.877209, -0.523275, -0.628435])/2 #np.set_printoptions(threshold=np.inf) #print(repr(disorder)) graph = line_graph(L) Heis = ham.HamiltonianHeisenberg(graph, energies=(1 / 4, 1 / 4), subspace='all') def matvec_disorder(x): if len(x.shape) == 2: return matvec_heisenberg(Heis, disorder, State(x)) else: return matvec_heisenberg(Heis, disorder, State(np.expand_dims(x, axis=-1))) disorder_heis = sp.sparse.linalg.LinearOperator((2**L, 2**L), matvec=matvec_disorder) dill.dump(disorder_heis, open('heisenberg_linear_op_' + str(graph.n) + '.pickle', 'wb')) if verbose: print('done with ham') # initial state: v0 = State(np.zeros((2**L, 1))) v0[0] = 1 p_checks = np.arange(1, 11) #nu_max = 7 #if verbose: # print('start kryl') #nmatvec, runtime, expk = krylov(disorder_heis, v0, tau, eps, p_check, nu_max, return_cost=True) #print('done kryl, {} matvec, {} s'.format(nmatvec, runtime)) tols = [1e-2, 1e-4, 1e-6] matvecs = np.zeros((len(tols), len(p_checks))) for (t, tol) in enumerate(tols): for (p, p_check) in enumerate(p_checks): if verbose: print('start cheb') nmatvec, runtime, expc = chebyshev(disorder_heis, v0, tau, tol, p_check, return_cost=True) matvecs[t, p] = nmatvec print('done cheb, {} matvec, {} s, {}'.format( nmatvec, runtime, p_check)) print(matvecs)
def rate_vs_eigenenergy(times, graph=line_graph(n=2), which='S'): """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus the final eigenenergy""" bad = np.arange(0, 2**graph.n, 1) if which == 'S': index = 0 elif which == 'L': index = -1 else: index = which bad = np.delete(bad, index) full_rates = np.zeros(len(bad)) # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule(t, tf): phi = (tf - t) / tf * np.pi / 2 x.energies = (np.sin(phi)**2, ) x = hamiltonian.HamiltonianDriver(graph=graph, IS_subspace=False, energies=(1, )) zz = hamiltonian.HamiltonianMaxCut(graph, cost_function=False, energies=(1 / 2, )) #dissipation = lindblad_operators.SpontaneousEmission(graph=graph, rates=(1,)) eq = SchrodingerEquation(hamiltonians=[x, zz]) 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 for i in range(len(times)): print(times[i]) schedule(times[i], 1) full_rates = full_rates + compute_rate() eigval, eigvec = eq.eig(k='all') return full_rates, eigval
def run(times, n=2, approximate=False): graph = line_graph(n) simulation = adiabatic_simulation(graph, approximate=approximate) def experiment_rydberg_MIS_schedule(t, tf, coefficients=None): if coefficients is None: coefficients = [1, 1, 1] if len(simulation.hamiltonian) == 2: for i in range(len(simulation.hamiltonian)): if i == 0: # We don't want to update normal detunings simulation.hamiltonian[i].energies = [ coefficients[0] * np.sin(np.pi * t / tf)**2 ] if i == 1: simulation.hamiltonian[i].energies = [ coefficients[1] * (2 * t / tf - 1) ] else: for i in range(len(simulation.hamiltonian)): if i == 0: # We don't want to update normal detunings simulation.hamiltonian[i].energies = [ coefficients[0] * np.sin(np.pi * t / tf) ] if i == 1: simulation.hamiltonian[i].energies = [ coefficients[1] * np.sin(np.pi * t / tf) ] if i == 3: simulation.hamiltonian[i].energies = [ coefficients[2] * (2 * t / tf - 1) ] return True # Omega_g * Omega_r / delta res = simulation.performance_vs_time( 2, schedule=lambda t, tf: experiment_rydberg_MIS_schedule( t, tf, coefficients=[Omega_g, Omega_r, Delta]), plot=True, verbose=False, method=['trotterize', 'odeint'], metric=['approximation_ratio', 'optimum_overlap']) return res
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 omega_vs_T(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() times = np.arange(20, 100, 10) omegas = np.arange(5, 8, .25) print(times, omegas) cost_function = [] for i in range(len(times)): cost_function_detuning = [] for j in range(len(omegas)): simulation = adiabatic_simulation(graph, noise_model='continuous', delta=omegas[j]) results = master_equation.run_ode_solver( psi, 0, times[i], num_from_time(times[i]), schedule=lambda t: schedule(t, times[i])) cost = rydberg_hamiltonian_cost.cost_function(results[-1], is_ket=False) / mis print(times[i], omegas[j], cost) cost_function_detuning.append(cost) cost_function.append(cost_function_detuning) plt.imshow(cost_function, vmin=0, vmax=1, interpolation=None, extent=[0, max(omegas), max(times), 0], origin='upper') plt.xticks(np.linspace(0, max(omegas), 10)) plt.yticks(np.linspace(0, max(times), 10)) plt.colorbar() plt.xlabel(r'Rabi frequency $\Omega$') plt.ylabel(r'Annealing time $T$') plt.show()
def run(n, t, gamma, omega): graph, mis = line_graph(n, return_mis=True) def rydberg_EIT_schedule(t, tf, coefficients=None): if coefficients is None: coefficients = [1, 1] for i in range(len(simulation_eit.hamiltonian)): if i == 0: # We don't want to update normal detunings simulation_eit.hamiltonian[i].energies = [t / tf * coefficients[0]] if i == 1: simulation_eit.hamiltonian[i].energies = [(tf - t) / tf * coefficients[1]] return True simulation_eit = eit_simulation(graph, noise_model='monte_carlo', gamma=gamma, delta=0) res = simulation_eit.performance_vs_total_time([t], schedule=lambda t, tf: rydberg_EIT_schedule(t, tf, coefficients=[omega, omega]), plot=False, verbose=True, method='odeint', iterations=1) return res
def time_performance(): graph, mis = line_graph(3, return_mis=True) # graph, mis = degree_fails_graph(return_mis=True) graph = Graph(graph) ratios_d = [1] ratios_r = [1] for d in ratios_d: for r in ratios_r: print(d, r) def rydberg_EIT_schedule(t, tf, coefficients=None): if coefficients is None: coefficients = [1, 1] for i in range(len(simulation_eit.hamiltonian)): if i == 0: # We don't want to update normal detunings simulation_eit.hamiltonian[i].energies = [ t / tf * coefficients[0] ] if i == 1: simulation_eit.hamiltonian[i].energies = [ (tf - t) / tf * coefficients[1] ] return True simulation_eit = eit_simulation(graph, noise_model='continuous', gamma=1, delta=d, Omega_g=r, Omega_r=r) simulation_eit.performance_vs_total_time( [5, 10, 15, 20], metric='cost_function', schedule=lambda t, tf: rydberg_EIT_schedule( t, tf, coefficients=[r, r]), plot=True, verbose=True, method='RK23')
def time_evolve(product_state, disorder, T, method='ED'): L = len(disorder) graph = line_graph(L) heisenberg = ham.HamiltonianHeisenberg(graph, energies=(1 / 4, 1 / 4), subspace=0) index = np.argwhere(np.sum(heisenberg.states - product_state, axis=1) == 0) state = np.zeros((heisenberg.states.shape[0], 1)) state[index] = 1 if method == 'ED': disorder_hamiltonian_diag = np.sum( (1 / 2 - heisenberg.states) * disorder, axis=1) disorder_hamiltonian = np.diag(disorder_hamiltonian_diag) eigval, eigvec = np.linalg.eigh(disorder_hamiltonian + heisenberg.hamiltonian) return eigvec @ (np.multiply( np.e**(-1j * T * np.expand_dims(eigval, axis=-1)), (eigvec.conj().T @ state))) elif method == 'expm_multiply': disorder_hamiltonian = sparse.csc_matrix( (np.sum((1 / 2 - heisenberg.states) * disorder, axis=1), (np.arange(heisenberg.states.shape[0]), np.arange(heisenberg.states.shape[0]))), shape=(heisenberg.states.shape[0], heisenberg.states.shape[0])) return expm_multiply( -1j * T * (disorder_hamiltonian + heisenberg.hamiltonian), state) elif method == 'expm': disorder_hamiltonian = sparse.csc_matrix( (np.sum((1 / 2 - heisenberg.states) * disorder, axis=1), (np.arange(heisenberg.states.shape[0]), np.arange(heisenberg.states.shape[0]))), shape=(heisenberg.states.shape[0], heisenberg.states.shape[0])) return expm(-1j * T * (disorder_hamiltonian + heisenberg.hamiltonian)) @ state else: raise NotImplementedError
def adiabatic_hamiltonian(t, tf): graph, mis = line_graph(n=n) ham = np.zeros((2**n, 2**n)) coefficients = adiabatic_schedule(t, tf) rydberg_energy = 50 rydberg_hamiltonian = hamiltonian.HamiltonianMIS(graph, energy=rydberg_energy, code=qubit) # TODO: generalize this! if n == 3: ham = ham + coefficients[1] * tools.tensor_product( [qubit.Z, np.identity(2), np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), qubit.Z, np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), np.identity(2), qubit.Z]) ham = ham + coefficients[0] * tools.tensor_product( [qubit.X, np.identity(2), np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), qubit.X, np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), np.identity(2), qubit.X]) ham = ham + np.diag(rydberg_hamiltonian.hamiltonian.T[0]) elif n == 2: ham = ham + coefficients[1] * tools.tensor_product( [qubit.Z, np.identity(2)]) ham = ham + coefficients[1] * tools.tensor_product( [np.identity(2), qubit.Z]) ham = ham + coefficients[0] * tools.tensor_product( [qubit.X, np.identity(2)]) ham = ham + coefficients[0] * tools.tensor_product( [np.identity(2), qubit.X]) ham = ham + np.diag(rydberg_hamiltonian.hamiltonian.T[0]) return np.linalg.eig(ham)
def performance_vs_alpha(): # alpha = gamma * omega^2/(delta^2 T) graph = line_graph(n=3) gammas = np.array([1, 5, 10]) times = np.array([1, 5, 10]) deltas = np.array([20, 30]) omegas = np.array([1, 5, 10]) for (g, d, o) in zip(gammas, deltas, omegas): # Find the performance vs alpha laser = EffectiveOperatorHamiltonian(graph=graph) dissipation = EffectiveOperatorDissipation(graph=graph) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=qubit) adiabatic = SimulateAdiabatic(hamiltonian=[laser], noise = [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) performance = adiabatic.performance_vs_total_time(times, schedule=schedule, verbose=True, method='odeint')[0] alphas = g * o**2/(d**2 * times) plt.scatter(alphas, performance) plt.show()
def imperfect_blockade_performance(): graph = line_graph(n=5, return_mis=False) phi = .02 laser = hamiltonian.HamiltonianDriver(pauli='X', energies=(np.cos(phi) * np.sin(phi),), graph=graph) energy_shift_r = hamiltonian.HamiltonianEnergyShift(index=0, energies=(np.sin(phi) ** 2,), graph=graph) energy_shift_g = hamiltonian.HamiltonianEnergyShift(index=1, energies=(np.cos(phi) ** 2,), graph=graph) dissipation = EffectiveOperatorDissipation(omega_g=np.cos(phi), omega_r=np.sin(phi), rates=(1,), graph=graph, IS_subspace=False) rydberg_hamiltonian = hamiltonian.HamiltonianMIS(graph, IS_subspace=False, code=qubit, energies=(0, 4,)) rydberg_hamiltonian_cost_IS = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=qubit) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=False, code=qubit, energies=(1, -4,)) eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift_g, energy_shift_r, rydberg_hamiltonian], jump_operators=[dissipation]) state = np.zeros(rydberg_hamiltonian_cost.hamiltonian.shape) state[graph.independent_sets[np.argmax(rydberg_hamiltonian_cost_IS.hamiltonian)][0], graph.independent_sets[np.argmax(rydberg_hamiltonian_cost_IS.hamiltonian)][0]] = 1 state = State(state, is_ket=False, graph=graph, IS_subspace=False) ss = eq.steady_state(state, k=80, use_initial_guess=True) print(ss[1].shape) ss = ss[1][0] print(np.diagonal(ss), rydberg_hamiltonian_cost.hamiltonian) state = State(ss, is_ket=False, graph=graph, IS_subspace=False) print(np.around(ss, decimals=3), rydberg_hamiltonian_cost.optimum_overlap(state)) layout = np.zeros((2, 2)) layout[0, 0] = 1 layout[1, 1] = 1 layout[0, 1] = 1 adjacent_energy = 4 diag_energy = adjacent_energy/8 second_nearest_energy = adjacent_energy/64 for i in range(layout.shape[0] - 1): for j in range(layout.shape[1] - 1): if layout[i, j] == 1: # There is a spin here pass
# coefficients=[Omega_g, Omega_r, Delta] [Omega, Delta] # res, info = simulation.run(20, schedule=lambda t, tf: True, verbose=True, method='odeint', iter=10) # print(res) # res, info = simulation.performance_vs_time(100, schedule=lambda t, tf: # experiment_rydberg_MIS_schedule(t, tf, coefficients=[Omega_g, Omega_r, Delta]), verbose=True, method='RK45', plot=True) # experiment_rydberg_MIS_schedule(t, tf, coefficients=[1, 1, 1]) # simulation.noise_model = None # simulation.performance_vs_time(10, schedule=lambda t, tf: experiment_rydberg_MIS_schedule(t, tf, coefficients=[15 * np.pi, 5.5 * np.pi, 2 * np.pi * 1.5]), # plot=True, method='odeint', verbose=True) # simulation.performance_vs_total_time(np.arange(5, 90, 5), schedule=lambda t, tf: simulation.rydberg_MIS_schedule(t, tf, # coefficients=[ # Omega, # Delta]), # plot=True, method='odeint', verbose=True) graph = line_graph(2) simulation_eit = eit_simulation(graph, noise_model='continuous', gamma=0, delta=25, Omega_g=5, Omega_r=5) """ performance = simulation_eit.run(2000, schedule=lambda t, tf: rydberg_EIT_schedule(t, tf, coefficients=[1, 1]), verbose=True, method='odeint') print(np.round(performance[0][-1], 2)) eigvals = simulation_eit.spectrum_vs_time(1, num=30, k=6, schedule=lambda t, tf: rydberg_EIT_schedule(t, tf, coefficients=[1, 1]), plot=True) """
layout[1, 1] = 1 layout[0, 1] = 1 adjacent_energy = 4 diag_energy = adjacent_energy/8 second_nearest_energy = adjacent_energy/64 for i in range(layout.shape[0] - 1): for j in range(layout.shape[1] - 1): if layout[i, j] == 1: # There is a spin here pass #imperfect_blockade_performance() graph = line_graph(n=3, return_mis=False) phi = np.pi/2 laser = EffectiveOperatorHamiltonian(omega_g=np.cos(phi), omega_r=np.sin(phi), graph=graph) eq = SchrodingerEquation(hamiltonians=[laser]) state = State(np.ones((5, 1), dtype=np.complex128)/np.sqrt(5)) print(np.round(eq.eig(k='all')[1], decimals=3)) def performance_vs_alpha(): # alpha = gamma * omega^2/(delta^2 T) graph = line_graph(n=3) gammas = np.array([1, 5, 10]) times = np.array([1, 5, 10]) deltas = np.array([20, 30]) omegas = np.array([1, 5, 10]) for (g, d, o) in zip(gammas, deltas, omegas):
def rate_vs_eigenenergy(times, graph=line_graph(n=2), mode='hybrid', which='S'): """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus the final eigenenergy""" if which == 'S': index = 0 elif which == 'L': index = -1 else: index = which # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule_hybrid(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.cos(phi) laser.omega_r = np.sin(phi) dissipation.omega_g = np.cos(phi) dissipation.omega_r = np.sin(phi) def schedule_reit(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) def schedule_adiabatic(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) laser.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) dissipation.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) dissipation.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) if mode == 'hybrid': schedule = schedule_hybrid elif mode == 'adiabatic': schedule = schedule_adiabatic elif mode == 'reit': schedule = schedule_reit if mode != 'reit': eq = SchrodingerEquation(hamiltonians=[laser, energy_shift]) else: eq = SchrodingerEquation(hamiltonians=[laser]) def compute_rate(): # Construct the first order transition matrix global full_rates energies, states = eq.eig(k='all') states = states.T rates = np.zeros(energies.shape[0]**2) for op in dissipation.jump_operators: rates = rates + (np.abs(states.conj().T @ op @ states)** 2).flatten() # Select the relevant rates from 'good' to 'bad' rates = np.reshape( rates.real, (graph.num_independent_sets, graph.num_independent_sets)) return rates[:, index].flatten() for i in range(len(times)): print(times[i]) schedule(times[i], 1) full_rates = compute_rate() eigval, eigvec = eq.eig(k='all') return full_rates, eigval
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()
def optimize_schedule(times, bad, graph=line_graph(n=2), initial_guesses=10): # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule_hybrid(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) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) schedule = schedule_hybrid eq = SchrodingerEquation(hamiltonians=[laser, energy_shift]) def optimize_delta_r(delta_r): delta_r = delta_r[0] energy_shift.energies = (delta_r, ) if bad == 'other': ground_energy, ground_state = eq.ground_state() overlap = 0 for op in dissipation.jump_operators: overlap = overlap + (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] - \ (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0] return overlap.real else: # Construct the first order transition matrix energies, states = eq.eig(k='all') states = states.T rates = np.zeros(energies.shape[0]**2) for op in dissipation.jump_operators: rates = rates + (np.abs(states.conj().T @ op @ states)** 2).flatten() # Select the relevant rates from 'good' to 'bad' rates = np.reshape( rates.real, (int(np.sqrt(rates.shape[0])), int(np.sqrt(rates.shape[0])))) rate = 0 for i in bad: rate += rates[i, 0] # print(time, rates, rate, delta_r) return rate delta_rs = [] rates = [] for time in times: print(time) schedule(time, 1) min_rate = np.inf min_delta_r = np.inf for i in range(initial_guesses): bounds = [-3, 3] rand = np.random.uniform(bounds[0], bounds[1], 1) delta_r = scipy.optimize.minimize(lambda dr: optimize_delta_r(dr), rand, bounds=[bounds]) print(time, delta_r.x[0], delta_r.fun) if delta_r.fun < min_rate: min_delta_r = delta_r.x[0] min_rate = delta_r.fun delta_rs.append(min_delta_r) rates.append(min_rate) return delta_rs, rates
def expansion(graph=line_graph(n=3), mode='reit', full_output=False, alpha_order=1, beta_order=1): # Find the performance vs alpha ground_energy = graph.independent_sets[0][1] degeneracy = 0 for IS in graph.independent_sets: if graph.independent_sets[IS][1] == ground_energy: degeneracy += 1 num = 100 if mode == 'reit': laser = EffectiveOperatorHamiltonian(graph=graph, omega_r=1, omega_g=1, energies=(1, )) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=qubit) def schedule_EIT(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) schedule = schedule_EIT eq = LindbladMasterEquation(hamiltonians=[laser], jump_operators=[dissipation]) if mode == 'adiabatic': def schedule_adiabatic(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (4 * np.sin(phi)**2 - np.cos(phi)**2, ) laser.energies = (np.cos(phi) * np.sin(phi), ) dissipation.rates = (np.cos(phi) * np.sin(phi), ) # Now run the standard adiabatic algorithm """laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1,), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4))""" laser = hamiltonian.HamiltonianDriver(graph=graph, IS_subspace=True, energies=(1, )) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(1, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) schedule = schedule_adiabatic eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation]) if mode == 'hybrid': def schedule_hybrid(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(phi)**2, ) # (- 1.35 * (t / tf - 1 / 2),) laser.omega_r = np.sin(phi) laser.omega_g = np.cos(phi) dissipation.omega_r = np.sin(phi) dissipation.omega_g = np.cos(phi) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) schedule = schedule_hybrid eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation]) # Compute orders in alpha # rho[o,:] = compute_alpha_order(rho[o-1,:], eq, schedule) # print(rho[o,-1,0,0]) if alpha_order == 1: rates = compute_first_alpha_order(eq, schedule, degeneracy, full_output=full_output) return rates rates = rates[:, 0] print(np.sum(rates[1:])) if degeneracy > 1: return -np.sum(rates) else: return rates if beta_order == 1: print('rate', compute_first_beta_order(eq, schedule).real)
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 alpha_correction_ar(graph=line_graph(n=2), mode='hybrid', angle=np.pi / 4, which='S', verbose=False): """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus the final eigenenergy""" if which == 'S': index = 0 elif which == 'L': index = graph.num_independent_sets - 1 else: index = which energies = [] bad_indices = [] target_energy = graph.independent_sets[index][1] degeneracy = 0 # Compute maximum independent set size and "bad" energies for IS in graph.independent_sets: if graph.independent_sets[IS][1] != target_energy: energies.append(graph.independent_sets[IS][1]) bad_indices.append(IS) else: degeneracy += 1 energies = np.array(energies) energies = np.abs(target_energy - energies) # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule_hybrid(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.cos(phi) laser.omega_r = np.sin(phi) dissipation.omega_g = np.cos(phi) dissipation.omega_r = np.sin(phi) def schedule_reit(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) def schedule_adiabatic(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.cos(angle) * np.sin(phi) * np.cos(phi) laser.omega_r = np.sin(angle) * np.sin(phi) * np.cos(phi) dissipation.omega_g = np.cos(angle) * np.cos(phi) * np.sin(phi) dissipation.omega_r = np.sin(angle) * np.cos(phi) * np.sin(phi) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) if mode == 'hybrid': schedule = schedule_hybrid elif mode == 'adiabatic': schedule = schedule_adiabatic elif mode == 'reit': schedule = schedule_reit if mode != 'reit': eq = SchrodingerEquation(hamiltonians=[laser, energy_shift]) else: eq = SchrodingerEquation(hamiltonians=[laser]) def compute_rate(t): if verbose: print(t) schedule(t, 1) # Construct the first order transition matrix eigval, eigvec = eq.eig(k='all') eigvec = eigvec.T rates = np.zeros(eigval.shape[0]**2) for op in dissipation.jump_operators: rates = rates + ((eigvec.conj().T @ op @ eigvec)**2).flatten() # Select the relevant rates from 'good' to 'bad' rates = np.reshape( rates.real, (graph.num_independent_sets, graph.num_independent_sets)) bad_rates = np.zeros(len(bad_indices)) for i in range(len(bad_indices)): bad_rates[i] = bad_rates[i] + rates[bad_indices[i], index] return np.dot(bad_rates, energies) # Integrate to find the correction res, error = scipy.integrate.quad_vec(compute_rate, 1e-5, .9999) return res / target_energy, error
rates = [ 0.010662442042852313, 0.016957472702683322, 0.02374938250983679, 0.03498899357236483, 0.043702391822540175, 0.054663814324193705, 0.06593339301684226 ] diss = [ 0.2927448927120103, 0.40019282741113876, 0.5126483512648607, 0.6198496428799345, 0.7245172743824079, 0.8360234218829589, 0.9456842157184615 ] print(np.diff(rates)) plt.plot(np.arange(4, 2 * len(diss) + 4, 2), diss) plt.scatter(np.arange(4, 2 * len(diss) + 4, 2), diss) plt.plot(np.arange(4, 2 * len(rates) + 4, 2), rates) plt.scatter(np.arange(4, 2 * len(rates) + 4, 2), rates, c='black') plt.show() if __name__ == "__main__": n = int(sys.argv[1]) res, error = alpha_correction_ar(graph=line_graph(n), mode='reit', which='S') print(res, error, flush=True) """ Compute <E>: - function which at a given time, computes all the "bad" rates and dots them with the difference between the final eigenvalues and the final ground state energy. """
def dissipation_over_time(times, delta_rs, graph=line_graph(n=2), mode='hybrid', which='S'): rates = np.zeros((len(delta_rs), len(times))) if which == 'S': index = 0 if which == 'L': index = graph.num_independent_sets - 1 optimal_energy = graph.independent_sets[index][1] degeneracy = 0 bad = [] for IS in graph.independent_sets: if graph.independent_sets[IS][1] == optimal_energy: degeneracy += 1 else: bad.append(IS) if degeneracy == 1: bad = 'other' # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule_hybrid(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) def schedule_adiabatic(t, tf): phi = (tf - t) / tf * np.pi / 2 laser.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) laser.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) dissipation.omega_g = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) dissipation.omega_r = np.sqrt(np.abs(np.sin(phi) * np.cos(phi))) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) if mode == 'hybrid': schedule = schedule_hybrid elif mode == 'adiabatic': schedule = schedule_adiabatic eq = SchrodingerEquation(hamiltonians=[laser, energy_shift]) def compute_rate(delta_r): energy_shift.energies = (delta_r, ) if bad == 'other' and which == 'S': ground_energy, ground_state = eq.ground_state() overlap = 0 for op in dissipation.jump_operators: overlap = overlap - (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] + \ (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0] return overlap.real else: # Construct the first order transition matrix energies, states = eq.eig(k='all') states = states.T rates = np.zeros(energies.shape[0]**2) for op in dissipation.jump_operators: rates = rates + (np.abs(states.conj().T @ op @ states)** 2).flatten() # Select the relevant rates from 'good' to 'bad' rates = np.reshape( rates.real, (int(np.sqrt(rates.shape[0])), int(np.sqrt(rates.shape[0])))) rate = 0 for i in bad: rate += rates[i, index] return rate for i in range(len(times)): print(times[i]) schedule(times[i], 1) for j in range(len(delta_rs)): rates[j, i] = compute_rate(delta_rs[j]) return rates
def expansion(mode='reit'): # Find the performance vs alpha graph = line_graph(n=2) num = 100 times = np.linspace(0, 1, 100) if mode == 'reit': laser = EffectiveOperatorHamiltonian(graph=graph, omega_r=1, omega_g=1, energies=(1, )) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) rydberg_hamiltonian_cost = hamiltonian.HamiltonianMIS(graph, IS_subspace=True, code=qubit) def schedule_EIT(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) """def compute_eigenenergies(t, y): schedule_EIT(t, 1) # Compute the Hamiltonian basis vectors eq = SchrodingerEquation(hamiltonians=[laser]) eigval, eigvec = eq.eig() return eigval """ #theta = \ # scipy.integrate.solve_ivp(compute_eigenenergies, (0, 1), np.zeros(eigval.shape), atol=1e-8, rtol=1e-6, # method='DOP853', t_eval=times)['y'].T schedule = schedule_EIT eq = LindbladMasterEquation(hamiltonians=[laser], jump_operators=[dissipation]) if mode == 'adiabatic': def schedule_adiabatic(t, tf): energy_shift.energies = (-5 * (t / tf - 1 / 2), ) laser.energies = (np.sin(t / tf * np.pi)**2, ) dissipation.rates = (np.sin(t / tf * np.pi)**2, ) # Now run the standard adiabatic algorithm laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) schedule = schedule_adiabatic eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation]) #rho = np.zeros((5, num, graph.num_independent_sets, graph.num_independent_sets), dtype=np.complex128) # Allow the integrator to allocate space. First get the zeroth order solution #psi0 = np.zeros((graph.num_independent_sets, graph.num_independent_sets)) #psi0[0, 0] = 1 # Convert results to density matrices #for i in range(num): # rho[0, i, :] = psi0 # Compute orders in alpha #rho[o,:] = compute_alpha_order(rho[o-1,:], eq, schedule) #print(rho[o,-1,0,0]) #print(compute_first_alpha_order(eq, schedule)) print(compute_first_beta_order(eq, schedule))
def leakage_vs_final_eigenenergy(times, graph=line_graph(n=2), mode='hybrid', angle=np.pi / 4, which='S'): """For REIT, compute the total leakage from the ground state to a given state. Plot the total leakage versus the final eigenenergy""" if which == 'S': index = 0 elif which == 'L': index = -1 else: index = which optimal_energy = graph.independent_sets[index][1] degeneracy = 0 bad = [] for IS in graph.independent_sets: if graph.independent_sets[IS][1] == optimal_energy: degeneracy += 1 else: bad.append(IS) if degeneracy == 1: bad = 'other' full_rates = np.zeros(graph.num_independent_sets - degeneracy) # Good is a list of good eigenvalues # Bad is a list of bad eigenvalues. If 'other', defaults to all remaining eigenvalues outside of 'good' def schedule_hybrid(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.cos(phi) laser.omega_r = np.sin(phi) dissipation.omega_g = np.cos(phi) dissipation.omega_r = np.sin(phi) def schedule_reit(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) def schedule_adiabatic(t, tf): phi = (tf - t) / tf * np.pi / 2 energy_shift.energies = (np.sin(2 * ((tf - t) / tf - 1 / 2) * np.pi), ) laser.omega_g = np.cos(angle) * np.sin(phi) * np.cos(phi) laser.omega_r = np.sin(angle) * np.sin(phi) * np.cos(phi) dissipation.omega_g = np.cos(angle) * np.cos(phi) * np.sin(phi) dissipation.omega_r = np.sin(angle) * np.cos(phi) * np.sin(phi) laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1, ), omega_g=np.cos(np.pi / 4), omega_r=np.sin(np.pi / 4)) energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, energies=(2.5, ), index=0) dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1, )) if mode == 'hybrid': schedule = schedule_hybrid elif mode == 'adiabatic': schedule = schedule_adiabatic elif mode == 'reit': schedule = schedule_reit if mode != 'reit': eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation]) else: eq = LindbladMasterEquation(hamiltonians=[laser], jump_operators=[dissipation]) def compute_rate(): if bad == 'other' and which == 'S': ground_energy, ground_state = eq.ground_state() overlap = 0 for op in dissipation.jump_operators: overlap = overlap - (np.abs(ground_state.conj().T @ op @ ground_state) ** 2)[0, 0] + \ (ground_state.conj().T @ op.conj().T @ op @ ground_state)[0, 0] return overlap.real else: # Construct the first order transition matrix energies, states = eq.eig(k='all') states = states.T rates = np.zeros(energies.shape[0]**2) for op in dissipation.jump_operators: rates = rates + (np.abs(states.conj().T @ op @ states)** 2).flatten() # Select the relevant rates from 'good' to 'bad' rates = np.reshape( rates.real, (int(np.sqrt(rates.shape[0])), int(np.sqrt(rates.shape[0])))) rate = 0 for i in bad: rate += rates[i, index] return rate return compute_first_alpha_order(eq, schedule, degeneracy, full_output=True)
def fidelity_vs_alpha(): graph = line_graph(5) omega = 100 T = 100 delta_e = 1000 beta = delta_e / (omega**2 * T) print('beta = ' + str(beta)) gammas = 10**np.linspace(1.75, 3.25, 3) print(gammas * omega**2 * T / delta_e**2) dissipation = EffectiveOperatorDissipation(0, 0, graph=graph, IS_subspace=True, rates=(1 / delta_e**2, )) laser = EffectiveOperatorHamiltonian(0, 0, energies=(1 / delta_e, ), graph=graph, IS_subspace=True) energy_shift = hamiltonian.HamiltonianEnergyShift(graph=graph, IS_subspace=True) def schedule_exp_fixed(t, tf=T): x = t / tf * np.pi / 2 amplitude = np.abs(np.cos(x) * np.sin(x)) # Now we need to figure out what the driver strengths should be for STIRAP omega_g = np.sin(x) * omega omega_r = np.cos(x) * omega offset = omega_r**2 - omega_g**2 # Now, choose the opposite of the STIRAP sequence energy_shift.energies = (offset / 1000, ) laser.omega_g = np.sqrt(amplitude) * omega laser.omega_r = np.sqrt(amplitude) * omega dissipation.omega_g = np.sqrt(amplitude) * omega dissipation.omega_r = np.sqrt(amplitude) * omega def schedule_reit(t, tf=T): x = t / tf * np.pi / 2 omega_g = np.sin(x) * omega omega_r = np.cos(x) * omega energy_shift.energies = (0, ) laser.omega_g = omega_g laser.omega_r = omega_r dissipation.omega_g = omega_g dissipation.omega_r = omega_r eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation]) nonoise_eq = SchrodingerEquation(hamiltonians=[laser, energy_shift]) state = State(np.array([[0, 0], [0, 1]], dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=False) state = State(np.array([[0, 0, 0], [0, 0, 0], [0, 0, 1]], dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=False) state = State(np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 1]], dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=False) state = State(np.zeros((13, 13), dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=False) state[-1, -1] = 1 # nonoise_state = State(np.array([[0], [0], [1]], dtype=np.complex128), IS_subspace=True, graph=graph, is_ket=True) # print(np.abs(nonoise_eq.run_ode_solver(nonoise_state, 0, T, num=500, schedule=schedule_exp_fixed, method='odeint')[0][-1])**2) for a in [1]: delta_e = a * 1000 laser.energies = (1 / delta_e, ) fidelities = [] ars = [] for i in range(len(gammas)): dissipation.rates = (gammas[i] / delta_e**2, ) states = eq.run_ode_solver(state, 0, T, num=50, schedule=schedule_reit, make_valid_state=False, method='odeint') times = states[1]['t'] states = states[0] """print(gammas[i], i) for j in range(len(times)): for op in dissipation.jump_operators: print(np.trace(op.conj().T@op@states[j])-np.abs(np.trace(op@states[j]))**2)""" """print(times[25]) schedule_exp_fixed(times[25], tf=T) eigvals, eigvecs = nonoise_eq.eig(k='all') print(eigvals) print(eigvecs.conj()@states[25]@eigvecs.T)""" final_state = states[-1] #print(final_state) #print(final_state[0, 0], np.trace(final_state)) ar = (final_state[0, 0] + 2 / 3 * (final_state[1, 1] + final_state[2, 2] + final_state[3, 3] + final_state[6, 6] + final_state[5, 5] + final_state[8, 8]) + 1 / 2 * (final_state[7, 7] + final_state[4, 4] + final_state[9, 9] + final_state[10, 10] + final_state[11, 11])) print(ar) print(final_state[0, 0]) print(final_state.diagonal()) ars.append(ar) fidelities.append(final_state[0, 0]) fidelities = np.array(fidelities) ars = np.array(ars) plt.loglog() plt.ylabel(r'$1-$ fidelity') plt.xlabel(r'$\frac{\gamma \Omega^2 T}{\delta_e^2}$') plt.plot(gammas * omega**2 * T / delta_e**2, 1 - fidelities, label='fidelity') plt.plot(gammas * omega**2 * T / delta_e**2, 1 - ars, label='ar') res = np.polyfit(np.log(gammas * omega**2 * T / delta_e**2), np.log(1 - fidelities), 1) print(res) #plt.plot(gammas * omega ** 2 * T / delta_e ** 2, # 1 - np.e ** (-gammas * omega ** 2 * T / delta_e ** 2 * 0.033875094811638556), # label='bound') """if a == -1: plt.plot(gammas * omega ** 2 * T / delta_e ** 2, 0.28187096704733217 * gammas * omega ** 2 * T / delta_e ** 2, label='first order correction') else: plt.plot(gammas * omega ** 2 * T / delta_e ** 2, 0.033875094811638556 * gammas * omega ** 2 * T / delta_e ** 2, label='first order correction')""" plt.legend() plt.tight_layout() plt.show()
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 for i in range(len(times)): print(times[i]) schedule(times[i], 1) full_rates = full_rates + compute_rate() eigval, eigvec = eq.eig(k='all') return full_rates, eigval n = 9 graph = line_graph(n) rates, eigvals = rate_vs_eigenenergy([.5], graph=graph, which='S') print(rates) eigvals = np.abs(eigvals - eigvals[0]) eigvals = np.delete(eigvals, 0) #plt.hist(eigvals, bins=30, weights=rates) #res = np.polyfit(eigvals, np.log(rates), 1) #print(res) # What is the energy spacing plt.scatter(eigvals, rates) #print(res[0]*np.mean(np.diff(eigvals)[0:6])) #plt.plot(eigvals, np.e**(res[0]*eigvals + res[1])) plt.semilogy() #plt.ylabel(r'$\sum_i \int_0^1 ds |\langle j |c_i| 0 \rangle|^2$') #plt.xlabel('final independendent set size') plt.ylabel(r'$\sum_i|\langle j |c_i| k \rangle|^2$')