# --- # jupyter: # jupytext: # formats: ipynb,py:percent # hide_notebook_metadata: false # text_representation: # extension: .py # format_name: percent # format_version: '1.3' # jupytext_version: 1.14.5 # kernelspec: # display_name: .venv # language: python # name: python3 # --- # %% [markdown] # Download Script # Download Job # #
#

Job Files for Complete Examples

#

# To be able to run the complete examples without having to submit your program to hardware and wait, you'll # need to download the associated job files. These files contain the results of running the program on # the quantum hardware. # # You can download the job files by clicking the "Download Job" button above. You'll then need to place # the job file in the `data` directory that was created for you when you ran the `import` part of the script # (alternatively you can make the directory yourself, it should live at the same level as wherever you put this script). #

#
# # %% [markdown] # # Nonequilibrium Dynamics of nearly Blockaded Rydberg Atoms # ## Introduction # In this example we will show how to generate multi-atom programs looking specifically # at the dynamics of two atoms that are right on the blockade radius. First let's start # with the imports. # %% import os import numpy as np import matplotlib.pyplot as plt from bloqade.analog import load, save from bloqade.analog.atom_arrangement import Chain if not os.path.isdir("data"): os.mkdir("data") # %% [markdown] # ## Program Definition # We will start by defining a program. We set up a chain of two atoms # with a parameterized distance between them. We then define a Rabi # like in the original Rabi oscillation example. Given a `rabi_ampl` of 15 rad/µs # the blockaded radius s 8.44 µm. We will look at the dynamics of the system for a # distance of 8.5 µm to be every so slightly outside of the blockade radius. We then # define a `batch` of programs for different `run_time` values. # %% initial_geometry = Chain(2, lattice_spacing="distance") program_waveforms = initial_geometry.rydberg.rabi.amplitude.uniform.piecewise_linear( durations=["ramp_time", "run_time", "ramp_time"], values=[0.0, "rabi_ampl", "rabi_ampl", 0.0], ) program_assigned_vars = program_waveforms.assign( ramp_time=0.06, rabi_ampl=15, distance=8.5 ) batch = program_assigned_vars.batch_assign(run_time=0.05 * np.arange(31)) # %% [markdown] # ## Run Emulator and Hardware # Once again we will run the emulator and hardware. We will use the # `local_emulator` method to run the emulator locally. We will then # save the results to a file so that we can use them later. # %% emu_filename = os.path.join( os.path.abspath(""), "data", "nonequilibrium-dynamics-blockade-emulation.json" ) if not os.path.isfile(emu_filename): emu_batch = batch.bloqade.python().run(10000) save(emu_batch, emu_filename) # %% [markdown] # When running on the hardware we will also parallelize the batch and submit. # #
#

Hardware Execution Cost

#

# # For this particular program, 31 tasks are generated with each task having 100 shots, amounting to # __USD \\$40.30__ on AWS Braket. # #

#
# %% filename = os.path.join( os.path.abspath(""), "data", "nonequilibrium-dynamics-blockade-job.json" ) if not os.path.isfile(filename): hardware_batch = batch.parallelize(24).braket.aquila().run_async(shots=100) save(hardware_batch, filename) # %% [markdown] # ## Plotting the Results # In order to show the complex dynamics we will plot the probability of having `0`, `1` # , or `2` Rydberg atoms as a function of time. We will do this for both the emulator # and the hardware. We can use the `rydberg_state_probabilities` function to extract # the probabilities from the counts. This function takes a list of counts and returns a # dictionary of probabilities for each state. The counts are obtained from the `report` # of the `batch` object. # %% def rydberg_state_probabilities(shot_counts): probabilities_dict = {"0": [], "1": [], "2": []} # iterate over each of the task results for task_result in shot_counts: # get total number of shots total_shots = sum(task_result.values()) # get probability of each state probabilities_dict["0"].append(task_result.get("11", 0) / total_shots) probabilities_dict["1"].append( (task_result.get("10", 0) + task_result.get("01", 0)) / total_shots ) probabilities_dict["2"].append(task_result.get("00", 0) / total_shots) return probabilities_dict # %% [markdown] # ## Extracting the counts and probabilities # We will now extract the counts and probabilities from the emulator and hardware runs. # We will then plot the results. First we load the data from the files. # %% emu_batch = load(emu_filename) emu_report = emu_batch.report() emu_counts = emu_report.counts() hardware_batch = load(filename) # hardware_batch.fetch() # uncomment to fetch results from Braket # save(filename, hardware_batch) # %% [markdown] # To get the `counts` we need to get a `report` from the `batch` objects. Then with the # report we can get the counts. The counts are a dictionary that maps the bitstring to # the number of times that bitstring was measured. # %% emu_report = emu_batch.report() hardware_report = hardware_batch.report() emu_rydberg_state_probabilities = rydberg_state_probabilities(emu_report.counts()) hw_rydberg_state_probabilities = rydberg_state_probabilities(hardware_report.counts()) # %% [markdown] # plot 0, 1, and 2 Rydberg state probabilities but in separate plots # %% figure, axs = plt.subplots(1, 3, figsize=(12, 6), sharey=True) emu_run_times = emu_report.list_param("run_time") hardware_run_times = hardware_report.list_param("run_time") emu_colors = ["#55DE79", "#EDFF1A", "#C2477F"] # Green, Yellow, Red emu_lines = [] hw_lines = [] for ax, rydberg_state, color in zip(axs, ["0", "1", "2"], emu_colors): (hw_line,) = ax.plot( emu_run_times, hw_rydberg_state_probabilities[rydberg_state], label=rydberg_state + "-Rydberg QPU", color=color, ) (emu_line,) = ax.plot( hardware_run_times, emu_rydberg_state_probabilities[rydberg_state], color="#878787", ) emu_line.set_label("Emulator") emu_lines.append(emu_line) hw_lines.append(hw_line) ax.set_xlabel("time ($\mu s$)") ax.set_ylabel("Probability") ax.legend(handles=[*hw_lines, emu_lines[-1]]) plt.show()