Rydberg back-end workflow demonstration¶
In cold atoms, we can also work with Rydberg atoms trapped in optical tweezers. This approach is widely used in companies like QuEra, Pasqal or AtomComputing.
As an example, we implemented here the operation such a tweezer array as it is implemented in various labs around the world. In this notebook we present the control with the API. The communication with the backend happens through the four url endpoints:
- '.../api/v2/rydberg/get_config/'
- '.../api/v2/rydberg/post_job/'
- '.../api/v2/rydberg/get_job_status/'
- '.../api/v2/rydberg/get_job_result/'
An interactive documentation can be also found directly online under the docs.
You can use this tutorial in two ways. For testing of local deployments of qlued
or the hosted version provided by Alqor.
Optional: Preparation for local deployment¶
To get started locally you have to:
- Apply any migrations to your local server
python manage.py migrate
- Start the server in a tab as
python manage.py runserver
- You created an account and saved the credentials this in the local
credentials_v2.py
file at the same location as this notebook. It should contain a variable entry calledusername
and one calledpassword
.
An example content looks like this:
username = "YOUR-USERNAME"
token = "YOUR-TOKEN"
Get the configuration¶
In a first step, we will try to see what are the available backends and what are the capabilities.
This can be done through the json API endpoints get_config
and backends
import requests
import json
from pprint import pprint
import numpy as np
import matplotlib.pyplot as plt
This imports the credentials_v2.py
file that contains the values of username
and token
. They were exported from this notebook for security reasons.
from credentials_v2 import username, token
# for local deployment uncomment the following line
# host_url = 'http://localhost:8000/'
# for work with the cloud version uncomment the following line
host_url = "https://qlued.alqor.io/"
Let us get the general configuration of all the backends first, to find the Rydberg back-end.
url = host_url + "api/v2/backends"
r = requests.get(url)
pprint(r.json())
[{'backend_name': 'alqor_fermionic_tweezer_simulator', 'backend_version': '0.0.1', 'basis_gates': ['fhop', 'fint', 'fphase'], 'cold_atom_type': 'fermion', 'conditional': False, 'coupling_map': 'linear', 'description': 'simulator of a fermionic tweezer hardware. The even wires ' 'denote the occupations of the spin-up fermions and the odd ' 'wires denote the spin-down fermions', 'display_name': 'fermions', 'dynamic_reprate_enabled': False, 'gates': [{'coupling_map': [[0, 1, 2, 3], [2, 3, 4, 5], [4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], 'description': 'hopping of atoms to neighboring tweezers', 'name': 'fhop', 'parameters': ['j_i'], 'qasm_def': '{}'}, {'coupling_map': [[0, 1, 2, 3, 4, 5, 6, 7]], 'description': 'on-site interaction of atoms of opposite spin ' 'state', 'name': 'fint', 'parameters': ['u'], 'qasm_def': '{}'}, {'coupling_map': [[0, 1], [2, 3], [4, 5], [6, 7], [0, 1, 2, 3, 4, 5, 6, 7]], 'description': 'Applying a local phase to tweezers through an ' 'external potential', 'name': 'fphase', 'parameters': ['mu_i'], 'qasm_def': '{}'}], 'local': False, 'max_experiments': 1000, 'max_shots': 1000000, 'memory': True, 'n_qubits': 8, 'num_species': 2, 'open_pulse': False, 'simulator': True, 'supported_instructions': ['load', 'barrier', 'fhop', 'fint', 'fphase', 'measure'], 'url': 'https://qlued.alqor.io/api/v2/fermions/', 'wire_order': 'interleaved'}, {'backend_name': 'alqor_multiqudit_simulator', 'backend_version': '0.0.1', 'basis_gates': ['rlx', 'rlz', 'rlz2', 'rlxly', 'rlzlz'], 'cold_atom_type': 'spin', 'conditional': False, 'coupling_map': 'linear', 'description': 'Setup of a cold atomic gas experiment with a multiple ' 'qudits.', 'display_name': 'multiqudit', 'dynamic_reprate_enabled': False, 'gates': [{'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under Lx', 'name': 'rlx', 'parameters': ['omega'], 'qasm_def': 'gate lrx(omega) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under the Z gate', 'name': 'rlz', 'parameters': ['delta'], 'qasm_def': 'gate rlz(delta) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under lz2', 'name': 'rlz2', 'parameters': ['chi'], 'qasm_def': 'gate rlz2(chi) {}'}, {'coupling_map': [[0, 1], [1, 2], [2, 3], [3, 4], [0, 1, 2, 3, 4]], 'description': 'Entanglement between neighboring gates with an xy ' 'interaction', 'name': 'rlxly', 'parameters': ['J'], 'qasm_def': 'gate rlylx(J) {}'}, {'coupling_map': [[0, 1], [1, 2], [2, 3], [3, 4], [0, 1, 2, 3, 4]], 'description': 'Entanglement between neighboring gates with a zz ' 'interaction', 'name': 'rlzlz', 'parameters': ['J'], 'qasm_def': 'gate rlzlz(J) {}'}], 'local': False, 'max_experiments': 1000, 'max_shots': 1000000, 'memory': True, 'n_qubits': 4, 'num_species': 1, 'open_pulse': False, 'simulator': True, 'supported_instructions': ['rlx', 'rlz', 'rlz2', 'rlxly', 'rlzlz', 'barrier', 'measure', 'load'], 'url': 'https://qlued.alqor.io/api/v2/multiqudit/', 'wire_order': 'interleaved'}, {'backend_name': 'alqor_singlequdit_simulator', 'backend_version': '0.0.2', 'basis_gates': ['rlx', 'rlz', 'rlz2'], 'cold_atom_type': 'spin', 'conditional': False, 'coupling_map': 'linear', 'description': 'Setup of a cold atomic gas experiment with a single qudit.', 'display_name': 'singlequdit', 'dynamic_reprate_enabled': False, 'gates': [{'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under Lx', 'name': 'rlx', 'parameters': ['omega'], 'qasm_def': 'gate lrx(omega) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under the Z gate', 'name': 'rlz', 'parameters': ['delta'], 'qasm_def': 'gate rlz(delta) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under lz2', 'name': 'rlz2', 'parameters': ['chi'], 'qasm_def': 'gate rlz2(chi) {}'}], 'local': False, 'max_experiments': 1000, 'max_shots': 1000000, 'memory': True, 'n_qubits': 1, 'num_species': 1, 'open_pulse': False, 'simulator': True, 'supported_instructions': ['rlx', 'rlz', 'rlz2', 'barrier', 'measure', 'load'], 'url': 'https://qlued.alqor.io/api/v2/singlequdit/', 'wire_order': 'interleaved'}, {'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'basis_gates': ['rlx', 'rlz', 'rydberg_block', 'rydberg_full'], 'cold_atom_type': 'spin', 'conditional': False, 'coupling_map': 'linear', 'description': 'A chain of qubits realized through Rydberg atoms.', 'display_name': 'rydberg', 'dynamic_reprate_enabled': False, 'gates': [{'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under Rlx', 'name': 'rlx', 'parameters': ['omega'], 'qasm_def': 'gate rlx(omega) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under the Rlz gate', 'name': 'rlz', 'parameters': ['delta'], 'qasm_def': 'gate rlz(delta) {}'}, {'coupling_map': [[0, 1, 2, 3, 4]], 'description': 'Apply the Rydberg blockade over the whole array', 'name': 'rydberg_block', 'parameters': ['phi'], 'qasm_def': 'gate rydberg_block(phi) {}'}, {'coupling_map': [[0, 1, 2, 3, 4]], 'description': 'Apply the Rydberg and Rabi coupling over the ' 'whole array.', 'name': 'rydberg_full', 'parameters': ['omega, delta, phi'], 'qasm_def': 'gate rydberg_full(omega, delta, phi) {}'}], 'local': False, 'max_experiments': 1000, 'max_shots': 1000000, 'memory': True, 'n_qubits': 5, 'num_species': 1, 'open_pulse': False, 'simulator': True, 'supported_instructions': ['rlx', 'rlz', 'rydberg_block', 'rydberg_full', 'barrier', 'measure'], 'url': 'https://qlued.alqor.io/api/v2/rydberg/', 'wire_order': 'interleaved'}]
As we go through the output above we can see that the last backend is the Rydberg simulator, we would like to use through out the rest of this tutorial. We can also get the configuration of this backend specifically through the endpoint get_config
and the display_name
.
url_prefix = host_url + "api/v2/rydberg/"
url = url_prefix + "get_config"
pprint(url)
r = requests.get(url)
pprint(r.json())
'https://qlued.alqor.io/api/v2/rydberg/get_config' {'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'basis_gates': ['rlx', 'rlz', 'rydberg_block', 'rydberg_full'], 'cold_atom_type': 'spin', 'conditional': False, 'coupling_map': 'linear', 'description': 'A chain of qubits realized through Rydberg atoms.', 'display_name': 'rydberg', 'dynamic_reprate_enabled': False, 'gates': [{'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under Rlx', 'name': 'rlx', 'parameters': ['omega'], 'qasm_def': 'gate rlx(omega) {}'}, {'coupling_map': [[0], [1], [2], [3], [4]], 'description': 'Evolution under the Rlz gate', 'name': 'rlz', 'parameters': ['delta'], 'qasm_def': 'gate rlz(delta) {}'}, {'coupling_map': [[0, 1, 2, 3, 4]], 'description': 'Apply the Rydberg blockade over the whole array', 'name': 'rydberg_block', 'parameters': ['phi'], 'qasm_def': 'gate rydberg_block(phi) {}'}, {'coupling_map': [[0, 1, 2, 3, 4]], 'description': 'Apply the Rydberg and Rabi coupling over the whole ' 'array.', 'name': 'rydberg_full', 'parameters': ['omega, delta, phi'], 'qasm_def': 'gate rydberg_full(omega, delta, phi) {}'}], 'local': False, 'max_experiments': 1000, 'max_shots': 1000000, 'memory': True, 'n_qubits': 5, 'num_species': 1, 'open_pulse': False, 'simulator': True, 'supported_instructions': ['rlx', 'rlz', 'rydberg_block', 'rydberg_full', 'barrier', 'measure'], 'url': 'https://qlued.alqor.io/api/v2/rydberg/', 'wire_order': 'interleaved'}
The above json gives us all kind of information on the backend, quite importantly also the gates that we can work with and their limitations. As we can see the backend implements the following gates:
rlx
which applies a $x$ local rotation to the qubit.rlz
which applies a $x$ local rotation to the qubit.rydberg_block
which describes interactions between rydberg atoms.measure
which reads out the occupation.
More information about the source code can be found here.
Deploying a first gate: Rlx¶
We will now start with a local $x$ rotation. We have to set up the json
dictionary that contains all the required information:
- One experiment.
- We perform a $\pi$ pulse on wire zero.
- We read it out.
- We perform only four shots and we run the simulator with two wires of the five allowed wires.
job_payload = {
"experiment_0": {
"instructions": [
("rlx", [0], [np.pi]),
("measure", [0], []),
],
"num_wires": 2,
"shots": 4,
"wire_order": "sequential",
},
}
Now, that we set up the instruction, we can submit it via the post_job
endpoint.
url = url_prefix + "post_job"
pprint(url)
job_response = requests.post(
url,
json={"job": json.dumps(job_payload), "username": username, "token": token},
)
job_id = (job_response.json())["job_id"]
print(job_response.json())
'https://qlued.alqor.io/api/v2/rydberg/post_job' {'job_id': '20230429_084359-rydberg-fred-385ed', 'status': 'INITIALIZING', 'detail': 'Got your json.', 'error_message': 'None'}
The simulator has now put the job into the queue and we will have to wait until the calculation is finished. To see its test the job status through get_job_status
.
url = url_prefix + "get_job_status"
status_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
print(status_response.text)
{"job_id": "20230429_084359-rydberg-fred-385ed", "status": "INITIALIZING", "detail": "Got your json.", "error_message": "None"}
As we can see the job is finished, so let us see the results the get_job_result
endpoint.
url = url_prefix + "get_job_result"
result_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
pprint(result_response.json())
{'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'header': {}, 'job_id': '20230429_084359-rydberg-fred-385ed', 'qobj_id': None, 'results': [{'data': {'memory': ['1', '1', '1', '1']}, 'header': {'extra metadata': 'text', 'name': 'experiment_0'}, 'shots': 4, 'success': True}], 'status': 'finished', 'success': True}
As expected, we obtained the same result for all shots. Let's move on to the more interesting case of a Rabi oscillation.
Rabi oscillation¶
In the Rabi oscillation, we actually perform the following series of experiments:
- We create a number of experiments called
experiment_XX
. - Each one applies a $\pi$ pulse of a different length
phase[ii]
. - We perform 9 shots for each pulse.
n_phases = 11 # number of phases we would like to investigate
phases = np.linspace(0, 2 * np.pi, n_phases) # array of phases
job_payload = {}
for ii in range(n_phases):
exp_str = "experiment_" + str(ii)
dummy_exp = {
"instructions": [
("rlx", [0], [phases[ii]]),
("measure", [0], []),
("measure", [1], []),
],
"num_wires": 2,
"shots": 9,
}
job_payload[exp_str] = dummy_exp
pprint(job_payload)
{'experiment_0': {'instructions': [('rlx', [0], [0.0]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_1': {'instructions': [('rlx', [0], [0.6283185307179586]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_10': {'instructions': [('rlx', [0], [6.283185307179586]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_2': {'instructions': [('rlx', [0], [1.2566370614359172]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_3': {'instructions': [('rlx', [0], [1.8849555921538759]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_4': {'instructions': [('rlx', [0], [2.5132741228718345]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_5': {'instructions': [('rlx', [0], [3.141592653589793]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_6': {'instructions': [('rlx', [0], [3.7699111843077517]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_7': {'instructions': [('rlx', [0], [4.39822971502571]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_8': {'instructions': [('rlx', [0], [5.026548245743669]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_9': {'instructions': [('rlx', [0], [5.654866776461628]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}}
Time to submit, test the job status and obtain the results.
url = url_prefix + "post_job"
pprint(url)
job_response = requests.post(
url,
json={"job": json.dumps(job_payload), "username": username, "token": token},
)
job_id = (job_response.json())["job_id"]
print(job_response.json())
'https://qlued.alqor.io/api/v2/rydberg/post_job' {'job_id': '20230429_084440-rydberg-fred-2d76d', 'status': 'INITIALIZING', 'detail': 'Got your json.', 'error_message': 'None'}
url = url_prefix + "get_job_status"
status_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
print(status_response.text)
{"job_id": "20230429_084440-rydberg-fred-2d76d", "status": "DONE", "detail": "None; Passed json sanity check; Compilation done. Shots sent to solver.", "error_message": "None"}
url = url_prefix + "get_job_result"
result_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
results_dict = result_response.json()
pprint(results_dict)
{'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'header': {}, 'job_id': '20230429_084440-rydberg-fred-2d76d', 'qobj_id': None, 'results': [{'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_0'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '1 0', '0 0', '0 0', '0 0', '0 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_1'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '0 0', '0 0', '1 0', '0 0', '1 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_2'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '0 0', '0 0', '1 0', '1 0', '1 0', '1 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_3'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_4'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_5'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '0 0', '1 0', '0 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_6'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '1 0', '0 0', '1 0', '0 0', '0 0', '0 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_7'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '1 0', '0 0', '1 0', '1 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_8'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_9'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_10'}, 'shots': 9, 'success': True}], 'status': 'finished', 'success': True}
and make the results pretty
measurements = []
for res in results_dict["results"]:
shots = np.array(res["data"]["memory"])
shots = [shot.split(" ") for shot in shots]
# print(shots.shape)
for ii, el in enumerate(shots):
shots[ii] = [int(meas) for meas in el]
measurements.append(shots)
measurements = np.array(measurements)
n0s = measurements[:, :, 0]
n1s = measurements[:, :, 1]
f, ax = plt.subplots(figsize=(5, 3))
ax.plot(phases, n0s, "rx", alpha=0.1)
ax.plot(phases, n0s.mean(axis=1), "ro", label="site 0")
ax.plot(phases, (1 - np.cos(phases)) / 2, "r-", lw=3)
ax.plot(phases, n1s, "bx", alpha=0.1)
ax.set_ylabel(r"spin up occupations")
ax.set_xlabel("$\\theta$")
ax.legend()
f.tight_layout()
Ramsey¶
We can also test a compination of $RX$ and $RZ$ gate through a Ramsey sequence, which we specify below.
n_phases = 11 # number of phases we would like to investigate
phases = np.linspace(0, 2 * np.pi, n_phases) # array of phases
job_payload = {}
for ii in range(n_phases):
exp_str = "experiment_" + str(ii)
dummy_exp = {
"instructions": [
("rlx", [0], [np.pi / 2]),
("rlz", [0], [phases[ii]]),
("rlx", [0], [np.pi / 2]),
("measure", [0], []),
("measure", [1], []),
],
"num_wires": 2,
"shots": 9,
}
job_payload[exp_str] = dummy_exp
pprint(job_payload)
{'experiment_0': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [0.0]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_1': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [0.6283185307179586]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_10': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [6.283185307179586]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_2': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [1.2566370614359172]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_3': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [1.8849555921538759]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_4': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [2.5132741228718345]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_5': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [3.141592653589793]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_6': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [3.7699111843077517]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_7': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [4.39822971502571]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_8': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [5.026548245743669]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}, 'experiment_9': {'instructions': [('rlx', [0], [1.5707963267948966]), ('rlz', [0], [5.654866776461628]), ('rlx', [0], [1.5707963267948966]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 9}}
url = url_prefix + "post_job"
pprint(url)
job_response = requests.post(
url,
json={"job": json.dumps(job_payload), "username": username, "token": token},
)
job_id = (job_response.json())["job_id"]
print(job_response.json())
'https://qlued.alqor.io/api/v2/rydberg/post_job' {'job_id': '20230429_084512-rydberg-fred-35739', 'status': 'INITIALIZING', 'detail': 'Got your json.', 'error_message': 'None'}
url = url_prefix + "get_job_status"
status_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
print(status_response.json())
{'job_id': '20230429_084512-rydberg-fred-35739', 'status': 'DONE', 'detail': 'None; Passed json sanity check; Compilation done. Shots sent to solver.', 'error_message': 'None'}
url = url_prefix + "get_job_result"
result_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
results_dict = result_response.json()
pprint(results_dict)
{'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'header': {}, 'job_id': '20230429_084512-rydberg-fred-35739', 'qobj_id': None, 'results': [{'data': {'memory': ['1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_0'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '0 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_1'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '0 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_2'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '1 0', '0 0', '1 0', '0 0', '0 0', '1 0', '1 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_3'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_4'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_5'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_6'}, 'shots': 9, 'success': True}, {'data': {'memory': ['0 0', '1 0', '0 0', '1 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_7'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '0 0', '0 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_8'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_9'}, 'shots': 9, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_10'}, 'shots': 9, 'success': True}], 'status': 'finished', 'success': True}
and make the results pretty
measurements = []
for res in results_dict["results"]:
shots = np.array(res["data"]["memory"])
shots = [shot.split(" ") for shot in shots]
# print(shots.shape)
for ii, el in enumerate(shots):
shots[ii] = [int(meas) for meas in el]
measurements.append(shots)
measurements = np.array(measurements)
n0s = measurements[:, :, 0]
n1s = measurements[:, :, 1]
f, ax = plt.subplots(figsize=(5, 3))
ax.plot(phases, n0s, "rx", alpha=0.1)
ax.plot(phases, n0s.mean(axis=1), "ro", label="site 0")
ax.plot(phases, (1 + np.cos(phases)) / 2, "r-", lw=3)
ax.plot(phases, n1s, "bx", alpha=0.1)
ax.set_ylabel(r"spin up occupations")
ax.set_xlabel("$\\theta$")
ax.legend()
f.tight_layout()
Blockade¶
The most interesting part is the Rydberg blockade. It allows us to entangle the atom, THE ingredient that is nowadays considered crucial for quantum speed-ups. To test it we will reproduce the results of this early paper, which demonstrate Rydberg blockade first.
n_phases = 11 # number of phases we would like to investigate
phases = np.linspace(0, 2 * np.pi, n_phases) # array of phases
job_payload = {}
for ii in range(n_phases):
exp_str = "experiment_" + str(ii)
dummy_exp = {
"instructions": [
("rydberg_full", [0, 1], [phases[ii], 0, phases[ii] * 1e2]),
("measure", [0], []),
("measure", [1], []),
],
"num_wires": 2,
"shots": 12,
}
job_payload[exp_str] = dummy_exp
pprint(job_payload)
{'experiment_0': {'instructions': [('rydberg_full', [0, 1], [0.0, 0, 0.0]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_1': {'instructions': [('rydberg_full', [0, 1], [0.6283185307179586, 0, 62.83185307179586]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_10': {'instructions': [('rydberg_full', [0, 1], [6.283185307179586, 0, 628.3185307179587]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_2': {'instructions': [('rydberg_full', [0, 1], [1.2566370614359172, 0, 125.66370614359172]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_3': {'instructions': [('rydberg_full', [0, 1], [1.8849555921538759, 0, 188.49555921538757]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_4': {'instructions': [('rydberg_full', [0, 1], [2.5132741228718345, 0, 251.32741228718345]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_5': {'instructions': [('rydberg_full', [0, 1], [3.141592653589793, 0, 314.1592653589793]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_6': {'instructions': [('rydberg_full', [0, 1], [3.7699111843077517, 0, 376.99111843077515]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_7': {'instructions': [('rydberg_full', [0, 1], [4.39822971502571, 0, 439.822971502571]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_8': {'instructions': [('rydberg_full', [0, 1], [5.026548245743669, 0, 502.6548245743669]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}, 'experiment_9': {'instructions': [('rydberg_full', [0, 1], [5.654866776461628, 0, 565.4866776461628]), ('measure', [0], []), ('measure', [1], [])], 'num_wires': 2, 'shots': 12}}
url = url_prefix + "post_job"
pprint(url)
job_response = requests.post(
url,
json={"job": json.dumps(job_payload), "username": username, "token": token},
)
job_id = (job_response.json())["job_id"]
print(job_response.json())
'https://qlued.alqor.io/api/v2/rydberg/post_job' {'job_id': '20230429_084536-rydberg-fred-1cf98', 'status': 'INITIALIZING', 'detail': 'Got your json.', 'error_message': 'None'}
url = url_prefix + "get_job_status"
status_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
print(status_response.text)
{"job_id": "20230429_084536-rydberg-fred-1cf98", "status": "DONE", "detail": "None; Passed json sanity check; Compilation done. Shots sent to solver.", "error_message": "None"}
url = url_prefix + "get_job_result"
result_response = requests.get(
url, params={"job_id": job_id, "username": username, "token": token}
)
results_dict_with_int = result_response.json()
pprint(results_dict_with_int)
{'backend_name': 'alqor_rydberg_simulator', 'backend_version': '0.0.3', 'header': {}, 'job_id': '20230429_084536-rydberg-fred-1cf98', 'qobj_id': None, 'results': [{'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_0'}, 'shots': 12, 'success': True}, {'data': {'memory': ['0 0', '0 1', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_1'}, 'shots': 12, 'success': True}, {'data': {'memory': ['0 1', '0 0', '1 0', '0 1', '0 1', '0 0', '0 1', '0 0', '0 1', '0 1', '0 1', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_2'}, 'shots': 12, 'success': True}, {'data': {'memory': ['1 0', '0 1', '0 0', '0 1', '1 0', '1 0', '0 1', '0 1', '0 1', '0 1', '0 1', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_3'}, 'shots': 12, 'success': True}, {'data': {'memory': ['0 0', '1 0', '1 0', '1 0', '1 0', '0 1', '0 1', '0 1', '0 1', '0 1', '1 0', '1 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_4'}, 'shots': 12, 'success': True}, {'data': {'memory': ['1 0', '0 1', '0 0', '1 0', '1 0', '0 0', '0 1', '0 0', '0 0', '0 0', '1 0', '0 1']}, 'header': {'extra metadata': 'text', 'name': 'experiment_5'}, 'shots': 12, 'success': True}, {'data': {'memory': ['0 1', '0 0', '0 0', '0 0', '1 0', '0 0', '0 0', '1 0', '0 0', '0 0', '1 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_6'}, 'shots': 12, 'success': True}, {'data': {'memory': ['0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_7'}, 'shots': 12, 'success': True}, {'data': {'memory': ['1 0', '0 0', '0 0', '0 0', '0 1', '0 0', '0 0', '0 0', '0 0', '0 0', '0 1', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_8'}, 'shots': 12, 'success': True}, {'data': {'memory': ['1 0', '0 1', '0 0', '0 1', '0 0', '0 1', '0 1', '1 0', '0 1', '0 1', '0 0', '0 0']}, 'header': {'extra metadata': 'text', 'name': 'experiment_9'}, 'shots': 12, 'success': True}, {'data': {'memory': ['1 0', '1 0', '1 0', '0 1', '1 0', '1 0', '1 0', '1 0', '1 0', '0 0', '0 1', '0 1']}, 'header': {'extra metadata': 'text', 'name': 'experiment_10'}, 'shots': 12, 'success': True}], 'status': 'finished', 'success': True}
measurements = []
for res in results_dict_with_int["results"]:
shots = np.array(res["data"]["memory"])
shots = [shot.split(" ") for shot in shots]
# print(shots.shape)
for ii, el in enumerate(shots):
shots[ii] = [int(meas) for meas in el]
measurements.append(shots)
measurements = np.array(measurements)
n0s = measurements[:, :, 0]
n1s = measurements[:, :, 1]
n_tot = n0s + n1s
f, ax = plt.subplots(figsize=(5, 3))
ax.plot(phases, n_tot, "rx", alpha=0.1)
ax.plot(phases, n_tot.mean(axis=1), "ro", label="average with blockade")
ax.plot(phases, (1 - np.cos(np.sqrt(2) * phases)) / 2, "r-")
ax.plot(phases, (1 - np.cos(phases)) / 2, "b-", label="no blockade")
ax.set_ylabel(r"spin up occupations")
ax.set_xlabel("$\\theta$")
ax.legend(loc="upper right")
f.tight_layout()