Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Learn how to submit a Qiskit quantum circuit using the azure-quantum Python package. You can submit Qiskit circuits to Azure Quantum using the Azure Quantum Development Kit (QDK) and Jupyter Notebook in Visual Studio Code (VS Code). You can also test your circuits using the local sparse simulator.
For more information, see Quantum circuits.
Prerequisites
For installation details, see Set up the QDK extension.
- An Azure Quantum workspace in your Azure subscription. To create a workspace, see Create an Azure Quantum workspace. 
- A Python environment with Python and Pip installed. 
- VS Code with the Azure Quantum Development Kit, Python, and Jupyter extensions installed. 
- The Azure Quantum - azure-quantumPython package with the [qiskit] tag.- python -m pip install --upgrade azure-quantum[qiskit] qsharp ipykernel- Important - Ensure that you have the latest version of Qiskit. For more information, see Update the azure-quantum Python package. - Note - If the Jupyter Python kernel - ipykernelis not detected, VS Code will prompt you to install it.
Create a new Jupyter Notebook
- In VS Code, select View > Command palette and select Create: New Jupyter Notebook.
- In the top-right, VS Code will detect and display the version of Python and the virtual Python environment that was selected for the notebook. If you have multiple Python environments, you may need to select a kernel using the kernel picker in the top right. If no environment was detected, see Jupyter Notebooks in VS Code for setup information.
Load the required imports
In the first cell of your notebook, run the following code to load the required imports:
import azure.quantum
from azure.quantum import Workspace 
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
from azure.quantum.qiskit import AzureQuantumProvider
Connect to the Azure Quantum service
To connect to the Azure Quantum service, your need the resource ID and the location of your Azure Quantum workspace.
- Log in to your Azure account, https://portal.azure.com, 
- Select your Azure Quantum workspace, and navigate to Overview. 
- Copy the parameters in the fields.   
Add a new cell in your notebook and use your account information to create Workspace and  AzureQuantumProvider objects to connect to your Azure Quantum workspace.
workspace = Workspace(  
    resource_id = "", # Add the resourceID of your workspace
    location = "" # Add the location of your workspace (for example "westus")
    )
provider = AzureQuantumProvider(workspace)
List all backends
You can now print all of the quantum computing backends that are available on your workspace:
print("This workspace's targets:")
for backend in provider.backends():
    print("- " + backend.name())
This workspace's targets:
- ionq.qpu
- ionq.qpu.aria-1
- ionq.simulator
- microsoft.estimator
- quantinuum.hqs-lt-s1
- quantinuum.hqs-lt-s1-apival
- quantinuum.hqs-lt-s2
- quantinuum.hqs-lt-s2-apival
- quantinuum.hqs-lt-s1-sim
- quantinuum.hqs-lt-s2-sim
- quantinuum.qpu.h2-1
- quantinuum.sim.h2-1sc
- quantinuum.sim.h2-1e
- rigetti.sim.qvm
- rigetti.qpu.ankaa-3
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 
Select a target to run your program
Run on the IonQ simulator
Before running on real hardware, let's test the circuit in the simulator. Use 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 aren't in this list, you need to transpile into the supported gateset using the transpile function provided by Qiskit:
from qiskit import transpile
circuit = transpile(circuit, simulator_backend)
The transpile function returns a new circuit object where gates are decomposed into gates that are supported on 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=8)
job_id = job.id()
print("Job id", job_id)
Job id 00000000-0000-0000-0000-000000000000
To wait until the job is complete and return the results, run:
result = job.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=8, success=True, meas_level=2, data=ExperimentResultData(counts={'000': 4, '111': 4}, memory=['000', '000', '000', '000', '111', '111', '111', '111'], probabilities={'000': 0.5, '111': 0.5}), header=QobjExperimentHeader(name='Qiskit Sample - 3-qubit GHZ circuit', num_qubits=3, metadata={}), status=JobStatus.DONE, name='Qiskit Sample - 3-qubit GHZ circuit')], date=None, status=None, header=None, error_data=None)
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': 4, '001': 0, '010': 0, '011': 0, '100': 0, '101': 0, '110': 0, '111': 4}

You can also use the get_memory() function to display individual shot data from the job
result.get_memory(circuit)
['000', '000', '000', '000', '111', '111', '111', '111']
Note
On IonQ targets, if you submit a job with an odd number of shots, the results will be rounded down to the next even number. For example, if you specify 9 shots, the results will display data for 8 shots.
Estimate job cost
Before running a job on the QPU, you should estimate how much it costs to run.
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.aria-1" to the get_backend method:
qpu_backend = provider.get_backend("ionq.qpu.aria-1")
Submit the circuit to run on Azure Quantum, get the results, and run plot_histogram to plot the results.
Note
The time required to run a circuit on the QPU may vary depending on current queue times.
# Submit the circuit to run on Azure Quantum
job = qpu_backend.run(circuit, shots=100)
job_id = job.id()
print("Job id", job_id)
# Get the job results (this method 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='ionq.qpu.aria-1', 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}

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())
Prerequisites
For installation details, see Set up the QDK extension.
- A Python environment with Python and Pip installed. 
- VS Code with the Azure Quantum Development Kit and Python extensions installed. 
- The Azure Quantum - qsharpPython package with the- qiskitand- widgettags.- python pip install "qsharp[qiskit,widgets]>=1.9"- Important - Ensure that you have the latest version of Qiskit. For more information, see Update the azure-quantum Python package. 
Run a basic circuit
In VS Code, open a new Python file to define and run a basic circuit with the built-in sparse simulator from the qsharp package.
# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# run the circuit using the built-in sparse simulator
backend = QSharpBackend()
job = backend.run(circuit)
counts = job.result().get_counts()
print(counts)
To run the program, select the Run icon in the upper right, and select Run Python file. The output displays in a new terminal window.
                  ┌─────────────────────────┐┌─┐
q_0: ─■───────────┤0                        ├┤M├───
      │P(0.79983) │  (XX-YY)(1.9337,1.7385) │└╥┘┌─┐
q_1: ─■───────────┤1                        ├─╫─┤M├
                  └─────────────────────────┘ ║ └╥┘
c: 2/═════════════════════════════════════════╩══╩═
                                              0  1
{'11': 680, '00': 344}
Generate QIR for the circuit
From that same circuit, you can generate QIR that's used to run on quantum hardware.
Note
To generate QIR, all registers must be measured into. If there are any unused registers, then an error is raised. Additionally, you get an error when you attempt to generate QIR with an Unrestricted target profile. The Unrestricted profile is only valid for simulation. You must use TargetProfile.Base, TargetProfile.Adaptive_RI, or TargetProfile.Adaptive_RIF. You can override the target_profile in the backend.qir(...) call to switch profiles.
- Import - QSharpErrorand- TargetProfile- from qsharp import QSharpError, TargetProfile
- To generate QIR, modify the output: - print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
Your code should now look like this:
# load the required imports 
from qiskit.circuit.random import random_circuit
from qsharp.interop.qiskit import QSharpBackend
from qsharp import QSharpError, TargetProfile
# define and display the circuit
circuit = random_circuit(2, 2, measure=True)
print(circuit)
# generate QIR for the circuit
print(backend.qir(circuit, target_profile=TargetProfile.Adaptive_RI))
Your code's output should look like this:
     ┌────────────┐             ┌─┐   
q_0: ┤ Rx(2.7195) ├─■───────────┤M├───
     └──┬─────┬───┘ │U1(5.5924) └╥┘┌─┐
q_1: ───┤ Tdg ├─────■────────────╫─┤M├
        └─────┘                  ║ └╥┘
c: 2/════════════════════════════╩══╩═
                                 0  1
%Result = type opaque
%Qubit = type opaque
define void @ENTRYPOINT__main() #0 {
block_0:
  call void @__quantum__qis__rx__body(double 2.7194945105768586, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 0 to %Qubit*))
  call void @__quantum__qis__t__adj(%Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__rz__body(double -2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__cx__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__rz__body(double 2.796204066686262, %Qubit* inttoptr (i64 1 to %Qubit*))
  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 0 to %Qubit*), %Result* inttoptr (i64 0 to %Result*))
  call void @__quantum__qis__m__body(%Qubit* inttoptr (i64 1 to %Qubit*), %Result* inttoptr (i64 1 to %Result*))
  call void @__quantum__rt__array_record_output(i64 2, i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 1 to %Result*), i8* null)
  call void @__quantum__rt__result_record_output(%Result* inttoptr (i64 0 to %Result*), i8* null)
  ret void
}
declare void @__quantum__qis__rx__body(double, %Qubit*)
declare void @__quantum__qis__rz__body(double, %Qubit*)
declare void @__quantum__qis__t__adj(%Qubit*)
declare void @__quantum__qis__cx__body(%Qubit*, %Qubit*)
declare void @__quantum__qis__m__body(%Qubit*, %Result*) #1
declare void @__quantum__rt__array_record_output(i64, i8*)
declare void @__quantum__rt__result_record_output(%Result*, i8*)
attributes #0 = { "entry_point" "output_labeling_schema" "qir_profiles"="adaptive_profile" "required_num_qubits"="2" "required_num_results"="2" }
attributes #1 = { "irreversible" }
; module flags
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!0 = !{i32 1, !"qir_major_version", i32 1}
!1 = !{i32 7, !"qir_minor_version", i32 0}
!2 = !{i32 1, !"dynamic_qubit_management", i1 false}
!3 = !{i32 1, !"dynamic_result_management", i1 false}
!4 = !{i32 1, !"classical_ints", i1 true}
!5 = !{i32 1, !"qubit_resetting", i1 true}
!6 = !{i32 1, !"classical_floats", i1 false}
!7 = !{i32 1, !"backwards_branching", i1 false}
!8 = !{i32 1, !"classical_fixed_points", i1 false}
!9 = !{i32 1, !"user_functions", i1 false}
!10 = !{i32 1, !"multiple_target_branching", i1 false}
Not all programs can run on all hardware. Here, if you try to target the Base profile, then you get detailed errors about which parts of the program aren't supported.
try:
    backend.qir(qc, target_profile=TargetProfile.Base)
except QSharpError as e:
    print(e)


