Quickstart: Submit a circuit with Qiskit to Azure Quantum

Learn how to use the azure-quantum Python package to submit Qiskit quantum circuits to an IonQ or Quantinuum quantum computing target via the Azure Quantum service. For more information, see Quantum circuits.

Prerequisites

Load the required imports

First, run the following cell to load the required imports:

from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.tools.monitor import job_monitor
from azure.quantum.qiskit import AzureQuantumProvider

Connect to the Azure Quantum service

To connect to the Azure Quantum service, your program will need the resource ID and the location of your Azure Quantum workspace. Log in to your Azure account, https://portal.azure.com, navigate to your Azure Quantum workspace, and copy the values from the header.

How to retrieve the resource ID and location from an Azure Quantum workspace

Paste the values into the following AzureQuantumProvider constructor to create a provider object that connects to your Azure Quantum workspace.

provider = AzureQuantumProvider(
  resource_id="",
  location=""
)

List all backends

You can now print all of the quantum computing backends that are available on your workspace:

print([backend.name() for backend in provider.backends()])
['ionq.qpu', 'ionq.simulator']

Run a simple circuit

First, create a simple Qiskit circuit to run.

# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])

# Print out the circuit
circuit.draw()
     ┌───┐          ┌─┐      
q_0: ┤ H ├──■───────┤M├──────
     └───┘┌─┴─┐     └╥┘┌─┐   
q_1: ─────┤ X ├──■───╫─┤M├───
          └───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
               └───┘ ║  ║ └╥┘
c: 3/════════════════╩══╩══╩═
                     0  1  2 

To get a result back quickly, use provider.get_backend to create a Backend object to connect to the IonQ Simulator backend:

simulator_backend = provider.get_backend("ionq.simulator")

IonQ backends support gates from a defined gateset, which are compiled to run optimally on the hardware. If your circuit contains gates that are not in this list, you'll need to transpile into the supported gateset using the transpile function provided by Qiskit:

from qiskit import transpile
circuit = transpile(circuit, simulator_backend)

This will return a new circuit object where gates are decomposed into gates that are supported by the specified backend.

You can now run the program via the Azure Quantum service and get the result. The following cell submits a job that runs the circuit with 100 shots:

job = simulator_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000

To monitor job progress, you can use the Qiskit job_monitor imported earlier to keep track of the Job's status. This call will block until the job completes:

job_monitor(job)
Job Status: job has successfully run

To wait until the job is complete and return the results, run:

result = job.result()

This returns a qiskit.Result object.

type(result)
qiskit.result.result.Result
print(result)
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=100, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 50, '111': 50}, probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(meas_map='[0, 1, 2]', name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])

Because the result is an object native to the Qiskit package, you can use Qiskit's result.get_counts and plot_histogram to visualize the results. To make sure that all possible bitstring labels are represented, add them to counts.

counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
{'000': 50, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 50}

Qiskit circuit result on IonQ Simulator

Estimate job cost

Before running a job on the QPU, you can estimate how much it will cost to run. To estimate the cost of running a job on the QPU, you can use the estimate_cost method:

backend = provider.get_backend("ionq.qpu")
cost = backend.estimate_cost(circuit, shots=100)

print(f"Estimated cost: {cost.estimated_total}")

This prints the estimated cost in USD.

For the most current pricing details, see IonQ Pricing, or find your workspace and view pricing options in the "Provider" tab of your workspace via: aka.ms/aq/myworkspaces.

Run on IonQ QPU

To connect to real hardware (a Quantum Processor Unit (QPU)), simply provide the name of the target "ionq.qpu" to the provider.get_backend method:

qpu_backend = provider.get_backend("ionq.qpu")

Submit the circuit to run on Azure Quantum.

Note

The time required to run a circuit on the QPU may vary depending on current queue times.

As before, use job_monitor to keep track of the job status, and plot_histogram to plot the results.

# Submit the circuit to run on Azure Quantum
qpu_job = qpu_backend.run(circuit, shots=1024)
job_id = qpu_job.id()
print("Job id", job_id)

# Monitor job progress and wait until complete:
job_monitor(qpu_job)

# Get the job results (this method also waits for the Job to complete):
result = qpu_job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='ionq.simulator', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'0': 505, '1': 6, '2': 1, '3': 1, '4': 1, '5': 10, '6': 11, '7': 488}, probabilities={'0': 0.4932, '1': 0.0059, '2': 0.001, '3': 0.001, '4': 0.001, '5': 0.0098, '6': 0.0117, '7': 0.4766}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits='3', qiskit='True'))])
{'000': 505, '001': 6, '010': 1, '011': 1, '100': 1, '101': 10, '110': 11, '111': 488}

Qiskit circuit result on IonQ QPU

Load the required imports

First, run the following cell to load the required imports:

from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from qiskit.tools.monitor import job_monitor
from azure.quantum.qiskit import AzureQuantumProvider

Connect to the Azure Quantum service

To connect to the Azure Quantum service, your program will need the resource ID and the location of your Azure Quantum workspace. Log in to your Azure account, https://portal.azure.com, navigate to your Azure Quantum workspace, and copy the values from the header.

How to retrieve the resource ID and location from an Azure Quantum workspace

Paste the values into the following AzureQuantumProvider constructor to create a provider object that connects to your Azure Quantum workspace.

provider = AzureQuantumProvider(
  resource_id="",
  location=""
)

List all backends

You can now print all of the quantum computing backends that are available on your workspace:

print([backend.name() for backend in provider.backends()])
    ['ionq.simulator', 'ionq.qpu', 'quantinuum.hqs-lt-s1', 'quantinuum.hqs-lt-s1-apival', 'quantinuum.hqs-lt-s1-sim']

Run on the API validator

Note

The Quantinuum API validator backend will always return 0 on measurement.

# Get Quantinuum's API validator backend:
apival_backend = provider.get_backend("quantinuum.hqs-lt-s1-apival")
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(3, 3)
circuit.name = "Qiskit Sample - 3-qubit GHZ circuit"
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure([0,1,2], [0, 1, 2])

# Print out the circuit
circuit.draw()
     ┌───┐          ┌─┐      
q_0: ┤ H ├──■───────┤M├──────
     └───┘┌─┴─┐     └╥┘┌─┐   
q_1: ─────┤ X ├──■───╫─┤M├───
          └───┘┌─┴─┐ ║ └╥┘┌─┐
q_2: ──────────┤ X ├─╫──╫─┤M├
               └───┘ ║  ║ └╥┘
c: 3/════════════════╩══╩══╩═
                     0  1  2 

Quantinuum backends support gates from a defined gateset which are compiled to run optimally on the hardware. If your circuit contains gates that are not in this list, you will need to transpile your circuit first into the supported gateset. For that, you can use the transpile function provided by Qiskit:

from qiskit import transpile
circuit = transpile(circuit, apival_backend)

This will return a new circuit object where gates are decomposed into gates that are supported by the specified backend.

# Submit the circuit to run on Azure Quantum
job = apival_backend.run(circuit, shots=1024)
job_id = job.id()
print("Job id", job_id)

# Monitor job progress and wait until complete:
job_monitor(job)

# Get the job results (this method also waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
Result(backend_name='quantinuum.hqs-lt-s1-apival', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 1024}, probabilities={'000': 1.0}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit'))])
{'000': 1024, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 0}

Qiskit circuit result on Quantinuum API validator

Estimate job cost

Before running a job on the QPU, you can estimate how much it will cost to run. To estimate the cost of running a job on the QPU, you can use the estimate_cost method:

qpu_backend = provider.get_backend("quantinuum.hqs-lt-s1")
cost = qpu_backend.estimate_cost(circuit, shots=1024)

print(f"Estimated cost: {cost.estimated_total}")

This prints the estimated cost in HQC, or "H1 Quantum Credits".

For the most current pricing details, see System Model H1, Powered by Honeywell, or find your workspace and view pricing options in the "Provider" tab of your workspace via: aka.ms/aq/myworkspaces.

Run on a Quantinuum QPU

After running successfully on the API validator, you can run your job on one of Quantinuum's hardware processors (a Quantum Processor Unit (QPU)).

Note

The time required to run a circuit on the QPU may vary depending on current queue times.

# Get Quantinuum's QPU backend:
qpu_backend = provider.get_backend("quantinuum.hqs-lt-s1")
# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=500)
job_id = job.id()
print("Job id", job_id)

# Monitor job progress and wait until complete:
job_monitor(job)
Job id 00000000-0000-0000-0000-000000000000
Job Status: job has successfully run
# Get the job results (this method also waits for the Job to complete):
result = job.result()
print(result)
counts = {format(n, "03b"): 0 for n in range(8)}
counts.update(result.get_counts(circuit))
print(counts)
plot_histogram(counts)
Result(backend_name='quantinuum.hqs-lt-s1-apival', backend_version='1', qobj_id='Qiskit Sample - 3-qubit GHZ circuit', job_id='00000000-0000-0000-0000-000000000000', success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, data=ExperimentResultData(counts={'011': 16, '010': 5, '001': 1, '000': 500, '111': 471, '101': 6, '100': 17, '110': 8}, probabilities={'011': 0.015625, '010': 0.0048828125, '001': 0.0009765625, '000': 0.48828125, '111': 0.4599609375, '101': 0.005859375, '100': 0.0166015625, '110': 0.0078125}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit'))])
{'000': 500, '001': 1, '010': 5, '011': 16, '100': 17, '101': 6, '110': 8, '111': 471}

Qiskit circuit result on Quantinuum QPU

Important

Submitting multiple circuits on a single job is currently not supported. As a workaround you can call the backend.run method to submit each circuit asynchronously, then fetch the results of each job. For example:

jobs = []
for circuit in circuits:
    jobs.append(backend.run(circuit, shots=N))

results = []
for job in jobs:
    results.append(job.result())