# Installation of tangelo if not already installed.
try:
import tangelo
except ModuleNotFoundError:
!pip install git+https://github.com/goodchemistryco/Tangelo.git@develop --quiet
Connecting to quantum services with Tangelo
Tangelo provides convenient ways to help you run experiments on quantum hardware. The tangelo.linq
module integrates the API provided by some hardware providers (IonQ, Honeywell…) or broader quantum cloud services providers such as Azure Quantum (Microsoft) or Braket (AWS). Here’s what Tangelo provides to support you:
Connection objects that act as a convenience wrapper for job management, which underneath uses whatever API the hardware provider exposed (qiskit-runtime, braket, Rest API…). It’s simple, covers most usage, and gets you submitting jobs in no time. No need to learn about all the different APIs !
Translation functions that can convert your quantum circuits and operators in the desired format (qiskit, braket, OpenQASM, IonQ JSON…). You can then use the API of your choice directly, for full control. Useful if you need very fine control and want to run an edge case not yet covered by the connection objects.
Regardless of what you pick: you are responsible for configuring the environment allowing you to submit jobs, and entering your own credentials. You are billed directly by the target quantum cloud service(s), Tangelo is simply here as a helpful, transparent middleman.
This approach is an alternative to using QEMIST Cloud, which we intend to make a single and convenient entry point to reach many different platforms. What’s pretty cool with this other option is that users do not have to set up the environment required by the quantum cloud(s) of their choice or even an account with those services. A QEMIST Cloud account provides a single entry point enabling you to reach all of them, and pay with your QEMIST Cloud credits.
Table of contents
Requirements
- Tangelo needs to be installed in your environment. The cell below does this installation for you if it is not found.
- The requirements specific to the target quantum services are detailed below, in the corresponding section. It’s usually about setting up your environment and obtaining valid credentials.
Method 1: Fine control (Translation functions)
In order to submit an experiment through some quantum services, you need to provide objects such as quantum circuits or qubit operators in one of the formats they support. For example, IBM may support formats such as OpenQASM and Qiskit, Amazon supports Braket, and your favorite hardware provider may support their own specific format using native gates not supported anywhere else.
Tangelo expresses quantum circuits and operators in its own generic format, in order to keep the library compatible with various technologies, and ready to accomodate the quantum platforms of tomorrow. The linq
module contains a collection of translation functions to convert from the Tangelo format to popular formats (and sometimes the other way around). If you haven’t, check out this notebook for examples.
Here is a simple example with IonQ, but there are various different formats supported in Tangelo. IonQ’s hardware is available through several cloud services, but they also have their own cloud portal. The following shows how to translate a Tangelo circuit into the json IonQ format detailed in their documentation.
from tangelo.linq import Circuit, Gate, translate_circuit
= Circuit([Gate("H", 0), Gate("X", 1)])
circ1 = translate_circuit(circ1, target="ionq")
json_circ1 print(json_circ1)
{'qubits': 2, 'circuit': [{'gate': 'h', 'targets': [0]}, {'gate': 'x', 'targets': [1]}]}
You now have a quantum circuit in a very specific format, supported by IonQ’s platforms. You can interact directly with their cloud API, and are in full control of all the steps: connecting to their quantum services, submitting and managing quantum jobs, etc.
Pros: Fine control, can leverage latest features / changes from a hardware provider.
Cons: You need to learn how to interact with the target platform (e.g their API), and are responsible for everything from there on to run the hardware experiment.
Method 2: Convenience (Connection classes)
Connection classes are here for convenience, to provide a simple, more generic way to connect to various platforms and manage experiments programmatically. We recommend that you do not hesitate to leverage whatever graphic interface / dashboard the target quantum service provider offers, as it is usually a more comfortable way to access and visualize a lot of information about the systems available or your jobs.
The connection classes spare you a number of lines of code and having to figure out a bunch of APIs, but you still have to install whatever your environment needs and provide your own valid credentials to the target services. Not all quantum services offer the same functionalities, or handle authentication similarly: we recommend you have a look at the classes themselves (the develop
branch may have additional features) to see what they have to offer or how they accomplish it.
Here’s how it typically works:
Step | Description |
---|---|
Pre-requisites | Install the required packages, acquire valid credentials for the target quantum service (check out their documentation) |
Create connection objects | Instantiate relevant connection object (e.g IBMConnection , BraketConnection , …). This usually requires you to provide your credentials either as parameters or through environment variables. |
Submit a job | Use the job_submit method. It takes your Tangelo objects as input and some options. It returns and logs job IDs |
Manage your job | Use job_status or job_cancel methods on jobs you’ve already submitted, through their job ID. |
Retrieve your results | Use the job_results method to retrieve your job results in a generic Tangelo format (bitstrings with qubit 0 on the left, read left-to-right), but also in raw format with all the metadata provided by the target service. |
Depending on the service, additional methods and features may be available (listing all devices visible on the service, obtaining information about their noise, cost estimate …). Let’s see a few examples.
1. BraketConnection example
1.1 Pre-requisites
Install the Braket python SDK provided by Amazon (pip install amazon-braket-sdk
). You also need to install the AWS CLI, and assumes you have an IAM user with proper permissions (Braket, S3 buckets). The Braket services can also be accessed through your web browser, which gives you access to managed python notebooks. These actions may require assistance from whoever manages cloud access in your organization.
Before you are able to use the service, some environment variables should be set. Depending on how you use Braket (managed notebooks, etc), you may or may have not to set all of these variables yourself. The following should be enough, replace the dots by the appropriate strings. Some of these information may be in your ~/.aws/credentials
file.
# Set up credentials [clear before pushing to public repo]
"AWS_REGION"] = "..."
os.environ["AWS_ACCESS_KEY_ID"] = "..."
os.environ["AWS_SECRET_ACCESS_KEY"] = "..."
os.environ["AWS_SESSION_TOKEN"] = "..." os.environ[
In order to submit experiments through Braket or retrieve results, you need to provide the name of a S3 bucket your account has access to, as well as a folder for the results. We recommend you ensure that is set up before proceeding.
1.2 Instantiate the connection object
As long as the Braket python package is found in your environment, instantiation will be successful. Your environment variables or S3 bucket / folder come into play later, as you attempt to make requests to the service. You can set up your S3 bucket name and folder during instantiation (or change their value manually later using the s3_bucket
and folder
attributes).
from tangelo.linq.qpu_connection.braket_connection import BraketConnection
= BraketConnection(s3_bucket="your_bucket_name", folder="your_folder_name") conn
1.3 Submit and manage jobs, additional features.
The fastest way to see things in action may be to check out our tests. It’s pretty straightforward.
This connection object supports batch submission of quantum circuits, which means you could provide a list of circuits and submit them all at once, otherwise your jobs may not run in similar conditions (quantum devices exhibit noise drift and are recalibrated regularly). To see all what the interface has to offer, the best way is to check out the implementation.
2. IBMConnection example
We have run an experiment on IBM devices for the IBM Quantum Summit of 2022, and it is probably the easiest way to see it in action. Section 4 of this notebook details the submission of the experiment itself using IBM Quantum, which involves Zero-Noise Extrapolation and plotting with error bars. You can find our implementation details here.
The gist of it:
- you need to install
qiskit
andqiskit-runtime
, and provide yourIBM_TOKEN
before instantiating the connection. - the interface is generic (
job_submit
,job_cancel
,job_results
, …).job_submit
can use thesampler
orestimator
services, which respectively return histograms of quasi-frequencies, or expectation values. - the interface supports a number of options for batch submission, optimization and noise-mitigation.
It’s pretty easy to create an account on IBM Quantum, and even get access to some quantum computers for free.
3. IonQConnection example
3.1 Pre-requisites
IonQ does not require any package in particular to be installed. As long as you can interact with their REST API, all is well. At the moment of writing, users allowed to use the IonQ API should have an ID token, e.g a string of alphanumeric characters and dashes, which can be obtained through the IonQ dashboard. Users need to set their IONQ_APIKEY
environment variable to this value; here are two ways to do it:
- in your terminal (
export IONQ_APIKEY=<value>
) - or, in your Python script (
os.environ['IONQ_APIKEY'] = <value>
)
Here’s an example of what it could look like for you (make sure you use a valid key, or you’ll get an “unauthorized” error :) )
import os
"IONQ_APIKEY"] = '2T14z1YQEzMLCwuYM110oXPDT2h850E4' os.environ[
3.2 Instantiate the connection object
The IonQConnection
class encapsulates a collection of wrappers to the IonQ REST API. Internally, it stores information about the endpoint and the authorization header, containing your identification token. This class only is instantiated succesfully if your ID token has been set properly, otherwise you’ll get an error.
More generally speaking, all calls to the REST API are checked for errors, and would return the IonQ error message corresponding to the unsuccessful request.
from tangelo.linq.qpu_connection import IonQConnection
= IonQConnection() ionq_connection
3.3 Submit and manage jobs, and additional features
Here we detail a number of features available using the IonQ portal.
Backend info
The get_backend_info
method returns some information about all the devices listed on IonQ’s platform. Tangelo currently returns this info inside a pandas.DataFrame
object, to help with visualization.
= ionq_connection.get_backend_info()
res # to display the dataframe neatly in this notebook res
backend | qubits | status | last updated | average queue time | characterization_url | |
---|---|---|---|---|---|---|
0 | qpu.harmony | 11 | available | 2022-07-29 06:16:04 | 735 | None |
1 | simulator | 19 | available | 2022-07-29 06:16:04 | 0 | None |
2 | qpu.s11 | 11 | available | 2022-07-29 06:16:04 | 735 | /characterizations/e8d7ac98-b7c2-443c-9eb8-105... |
This information can help users to filter or sort devices according to their needs. For example, filtering out devices who do not have enough qubits for the target experiment, as well as the unavailable devices.
We can also retrieve “characterizations”: a snapshot of the IonQ platform’s performance at a moment in time. We can use the get_characterization
method with either a backend string (ex: qpu.harmony
or simulator
) or a characterization url, if available (see dataframe above).
= ionq_connection.get_characterization('qpu.s11')
charac_dict print(charac_dict['fidelity'])
print(charac_dict['timing'])
{'1q': {'mean': 0.9979}, '2q': {'mean': 0.961}, 'spam': {'mean': 0.99752}}
{'t1': 10000, 't2': 0.2, '1q': 1e-05, '2q': 0.0002, 'readout': 0.00013, 'reset': 2e-05}
This information can help users having a better understanding of the capabilities of a device, and anticipate its performance on their usecases. Please check IonQ’s documentation to confirm what these quantities mean, and the units in which they are expressed in.
Job submission
Submit a job with the job_submit
method. It returns a job ID if submission was successful.
At the time of writing, this method takes input arguments that need to be provided by the user:
- the target backend (strings provided by IonQ to refer to their simulators or QPUs)
- the quantum circuit (in Tangelo format)
- the number of shots required
- a name for your job
- any other option as key arguments (see source code and IonQ documentation)
Assuming a valid API key, we here submit a simple job targeting their statevector simulator. The status of the job may be in various states (queued, ready, running …).
= ionq_connection.job_submit('simulator', circ1, 100, 'test_json_job') job_id
Job submission ID :: dfb38687-8c70-4b40-833d-c6166a902efe status :: ready
Job history and job info
Users can access their job history and info through the job_get_history
and job_status
methods, shown as below. But IonQ also provides an online dashboard, which may be more convenient to you.
Depending on the timing of your REST requests, the job info may differ widely, from a failed job to a completed job with results included.
= ionq_connection.job_status(job_id)
job_status print(job_status)
Job info ID:: dfb38687-8c70-4b40-833d-c6166a902efe status :: completed
{'status': 'completed', 'name': 'test_json_job', 'target': 'simulator', 'predicted_execution_time': 4, 'execution_time': 19, 'id': 'dfb38687-8c70-4b40-833d-c6166a902efe', 'qubits': 2, 'type': 'circuit', 'request': 1659075527, 'start': 1659075529, 'response': 1659075529, 'gate_counts': {'1q': 2}, 'data': {'histogram': {'2': 0.5, '3': 0.5}, 'registers': None}}
The output of job_get_history
should at least feature the job we just submitted, and can also show a number of previous jobs run under your account. The output is a pandas
dataframe, in order to facilitate parsing of information:
= ionq_connection.job_get_history()
job_history 5] # Here we only display info of the last 5 jobs run job_history[:
id | status | target | |
---|---|---|---|
0 | dfb38687-8c70-4b40-833d-c6166a902efe | completed | simulator |
1 | b486e66a-2ae2-4275-8c9e-015a751dcbbe | completed | simulator |
2 | 5dea41e0-ce02-4193-8e50-e48fc0cd0c22 | canceled | qpu.harmony |
3 | 34cc2763-f617-427a-8b3a-621086946a3b | completed | qpu.harmony |
4 | 777237b4-79e8-44d0-8ac6-762f24864e7a | completed | simulator |
Job results
The method job_results
provides a wrapper to a blocking call, querying for the state of the target job at regular intervals, attempting to retrieve the results. If the job has successfully completed, this method returns a dictionary with bitstring keys (ex: 01
, 11
…)
IonQ raw results use a “most-significant qubit first” representation, encoded as an integer, but Tangelo returns them as a bitstring in least-significant order (e.g we read left-to-right), to stay consistant with its own format and what is common across other cloud services.
For our example circuit, IonQ’s raw results would return {'2': 0.5, '3': 0.5}
with an exact simulator. - 2 is ‘10’ in binary, indicating \(q_0\) mesured in state \(|0\rangle\), and \(q_1\) in state \(|1\rangle\) - 3 is ‘11’ in binary, indicating \(q_0\) mesured in state \(|1\rangle\), and \(q_1\) in state \(|1\rangle\)
Tangelo returns {'01': 0.5, '11': 0.5}
.
= ionq_connection.job_results(job_id)
results print(results)
Job info ID:: dfb38687-8c70-4b40-833d-c6166a902efe status :: completed
{'01': 0.5, '11': 0.5}
Job cancel / delete
A wrapper called job_cancel
provides a method to cancel before execution (if the job hasn’t run yet), or delete a job from the history. The cell below cancels / deletes the previously-submitted job: it therefore should not appear in the history anymore.
ionq_connection.job_cancel(job_id)= ionq_connection.job_get_history()
job_history job_history
Job cancel ID :: dfb38687-8c70-4b40-833d-c6166a902efe status :: deleted
id | status | target | |
---|---|---|---|
0 | b486e66a-2ae2-4275-8c9e-015a751dcbbe | completed | simulator |
1 | 5dea41e0-ce02-4193-8e50-e48fc0cd0c22 | canceled | qpu.harmony |
2 | 34cc2763-f617-427a-8b3a-621086946a3b | completed | qpu.harmony |
3 | 777237b4-79e8-44d0-8ac6-762f24864e7a | completed | simulator |
4 | 9da8401b-5334-4358-ab3f-ddcd3e2f1ff4 | completed | simulator |
5 | 9dd67d5f-aa29-46fb-a707-1858d022aacc | completed | simulator |
6 | 45e33c7e-33bd-43d6-aef3-87b78e7bdd77 | completed | simulator |
7 | be130388-8daf-49dd-8e17-5b4c5274d69f | completed | simulator |
8 | 2c3526c0-44d4-4573-9bc1-c39a5c0135ae | completed | simulator |
9 | 373f3175-e7be-48cd-bf47-ac5e331a0eb0 | completed | simulator |
10 | b567e71c-fa20-4fb9-9ce9-62521de7a1ec | completed | simulator |
11 | b1743e6d-359c-4175-bf56-99b8662fdcaf | completed | simulator |
12 | f9865e17-25d8-4d84-b8f8-dc31e07a8fae | completed | simulator |
13 | e54a5d12-65e4-4fef-8774-68584ccad94c | completed | simulator |
14 | be0c8bc7-5539-4e4f-b12c-5370a525076d | completed | simulator |
4. Azure Quantum
A work in progress ! Though this package does not currently provide a way to directly submit jobs through Microsoft’s Azure Quantum cloud services, the tangelo.linq
module can parse an abstract circuit and generate Q# code that can be written to file, or other of the formats supported by Azure Quantum (cirq
, qiskit
, IonQ…). Check out their documentation for the most reliable information.
Some users have successfully submitted experiments to Azure Quantum by simply translating their Tangelo circuit into the desired format and adding measurement gates at the end of their circuit.
Our generated Q# code is compatible with both the local QDK simulator (good for testing before submitting to an actual QPU) or by Azure Quantum. Submission through Azure Quantum will require the user to have an account on Azure, install the local CLI and Python dependencies. For an example of how one can use this package to first generate circuits, and then submit jobs through Azure quantum, please look into the example/qsharp
folder of this package.
In the future, we intend to provide a connection object for Azure Quantum as well. Let us know if you would like us to prioritize this feature, or even help us implement it faster by contributing.