Your First Quantum Program: Gate-Based Quantum Computing on Azure with Python
Your First Quantum Program: Gate-Based Quantum Computing on Azure with Python
Part I of a series on quantum programming via cloud services
By Meiling Zhang & Salvatore Magnone
What This Article Covers
This article walks you through writing and running a quantum program on real quantum hardware using Python. By the end, you will have:
Set up a local development environment for quantum programming
Connected to Microsoft Azure Quantum
Written a quantum circuit that creates entanglement between two qubits
Run that circuit on a simulator and (optionally) on actual quantum hardware
Retrieved and interpreted the results
We will use Qiskit, an open-source Python library for quantum computing, running on Azure Quantum, Microsoft’s cloud platform that provides access to quantum hardware from multiple vendors.
The Software Stack: How the Pieces Fit Together
Before writing code, it helps to understand how your Python code eventually runs on quantum hardware. Here is the chain:
Your Python Code (Qiskit)
↓
OpenQASM (intermediate representation)
↓
Azure Quantum Service
↓
Hardware Provider (IonQ, Quantinuum, Rigetti, etc.)
↓
Physical Quantum Processor
Let me explain each layer.
Python is a general-purpose programming language. You probably already know it.
Qiskit (pronounced “kiss-kit”) is a Python library created by IBM for writing quantum programs. It lets you define quantum circuits, simulate them on your laptop, and submit them to cloud quantum services. Qiskit is open source and works with multiple cloud providers, including Azure Quantum. When you write Qiskit code, you are describing what quantum operations you want to perform, not how the hardware should perform them.
OpenQASM (Open Quantum Assembly Language, pronounced “open kazm”) is a text-based language for describing quantum circuits. Think of it as the “assembly language” of quantum computing. When you run a Qiskit program, Qiskit converts your Python circuit into OpenQASM. This intermediate representation can be understood by different quantum hardware backends. You rarely write OpenQASM directly, but you can inspect what Qiskit generates:
from qiskit import QuantumCircuit
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
print(circuit.qasm())
Output:
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
h q[0];
cx q[0],q[1];
This portability matters because different quantum computers have different physical implementations. OpenQASM provides a common language.
Azure Quantum is Microsoft’s cloud service for quantum computing. It does not build quantum hardware itself. Instead, it provides access to hardware from multiple companies:
IonQ: Uses trapped ions (charged atoms held in place by electromagnetic fields)
Quantinuum: Also uses trapped ions, with a different architecture
Rigetti: Uses superconducting circuits (similar to IBM and Google)
Pasqal: Uses neutral atoms
When you submit a job through Azure Quantum, the service routes your circuit to the hardware provider you select. Each provider also offers simulators that run on classical computers, which is useful for testing before using real hardware (which costs money).
At the bottom of the stack is the physical quantum processor. Your OpenQASM circuit gets compiled further into control signals specific to that hardware: microwave pulses for superconducting qubits, laser pulses for trapped ions, and so on. You do not need to understand this layer to write quantum programs. The cloud service handles it.
Terminology You Need
Before we set up the environment, here are the terms you will encounter:
Qubit: The basic unit of quantum information. Unlike a classical bit (which is either 0 or 1), a qubit can exist in a superposition of both states simultaneously. When you measure a qubit, the superposition collapses to either 0 or 1.
Gate: An operation that transforms qubit states. Gates are the quantum equivalent of logic gates in classical computing. Common gates include:
H (Hadamard): Puts a qubit into superposition
X (NOT): Flips a qubit from 0 to 1 or vice versa
CX (CNOT, Controlled-NOT): Flips a target qubit only if a control qubit is 1
Circuit: A sequence of gates applied to qubits, followed by measurements. This is what you build in Qiskit.
Shot: A single execution of your circuit. Because quantum measurements are probabilistic, you typically run many shots and look at the distribution of results.
Backend: The system that runs your circuit. A backend can be a simulator (runs on classical hardware) or a QPU (Quantum Processing Unit, actual quantum hardware).
Entanglement: A quantum phenomenon where two or more qubits become correlated in a way that has no classical equivalent. Measuring one qubit instantly determines the state of the other, regardless of distance.
Part 1: Setting Up Your Local Environment
You need Python 3.8 or later. Check your version:
python --version
Step 1: Create a Virtual Environment
A virtual environment keeps your quantum packages separate from other Python projects. This avoids version conflicts.
# Create a directory for your quantum projects
mkdir quantum-projects
cd quantum-projects
# Create a virtual environment
python -m venv quantum-env
# Activate it (Linux/Mac)
source quantum-env/bin/activate
# Activate it (Windows)
quantum-env\Scripts\activate
Your command prompt should now show (quantum-env) at the beginning.
Step 2: Install the Required Packages
Install the Azure Quantum package with Qiskit support:
pip install azure-quantum[qiskit]
This installs:
The azure-quantum package for connecting to Azure
Qiskit and its dependencies
Integration code that lets Qiskit talk to Azure backends
The installation may take a few minutes.
Step 3: Verify the Installation
Open a Python interpreter and check that imports work:
python
>>> from qiskit import QuantumCircuit
>>> from azure.quantum.qiskit import AzureQuantumProvider
>>> print("Setup successful")
Setup successful
>>> exit()
If you see no errors, your local environment is ready.
Part 2: Setting Up Azure Quantum
To run circuits on Azure (including their free simulators), you need an Azure account and a Quantum workspace.
Step 1: Create an Azure Account
If you do not have an Azure account:
Go to https://azure.microsoft.com/free/
Click “Start free”
Sign in with a Microsoft account or create one
Provide payment information (required, but you will not be charged for free-tier usage)
Azure offers free credits for new accounts. The simulators we will use in this tutorial are free or very low cost.
Step 2: Create a Quantum Workspace
A workspace is a container for your quantum jobs and results.
Go to https://portal.azure.com
In the search bar at the top, type “Azure Quantum” and select it
Click “Create”
Choose “Quick create” for the simplest setup
Fill in the required fields:
Subscription: Select your Azure subscription
Resource group: Create a new one (e.g., “quantum-rg”) or use an existing one
Workspace name: Choose a name (e.g., “my-quantum-workspace”)
Region: Pick a region near you (e.g., “East US”)
Click “Create”. Deployment takes about a minute.
Quick create automatically adds several providers: IonQ, Quantinuum, Rigetti, and Microsoft. Each provider offers simulators and (paid) access to real quantum hardware.
Step 3: Get Your Workspace Credentials
After deployment completes:
Go to your new workspace in the Azure portal
Click “Overview” in the left menu
Find and copy two values:
Resource ID: A long string starting with /subscriptions/...
Location: The region (e.g., “eastus”)
You will need these to connect from Python.
Part 3: Writing Your First Quantum Circuit
We will create a Bell state, which is the simplest example of quantum entanglement. A Bell state puts two qubits into a correlated superposition where:
If you measure the first qubit and get 0, the second qubit will also be 0
If you measure the first qubit and get 1, the second qubit will also be 1
This correlation holds 100% of the time, even though each individual measurement is random (50% chance of 0, 50% chance of 1).
The Circuit
Create a new file called bell_state.py:
from qiskit import QuantumCircuit
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt
# Create a circuit with 2 qubits and 2 classical bits
# The classical bits will store measurement results
circuit = QuantumCircuit(2, 2)
# Step 1: Apply Hadamard gate to qubit 0
# This puts qubit 0 into superposition
circuit.h(0)
# Step 2: Apply CNOT gate with qubit 0 as control, qubit 1 as target
# This entangles the two qubits
circuit.cx(0, 1)
# Step 3: Measure both qubits
circuit.measure([0, 1], [0, 1])
# Draw the circuit
print(circuit.draw())
Run this file:
python bell_state.py
Output:
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
Reading this diagram:
q_0 and q_1 are the two qubits
c: 2/ is the classical register (2 bits) that stores measurement results
H is the Hadamard gate
The vertical line with the dot and X is the CNOT gate (dot is control, X is target)
M boxes are measurements
Double lines show classical information flow
What Should Happen
When we run this circuit many times:
We should see roughly 50% of results as “00” (both qubits measured as 0)
We should see roughly 50% of results as “11” (both qubits measured as 1)
We should see almost no “01” or “10” results
This is entanglement: the qubits are correlated even though individual outcomes are random.
Part 4: Running on a Local Simulator
Before using cloud resources, test your circuit locally. Qiskit includes a simulator called Aer.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt
# Create the Bell state circuit
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])
print("Circuit:")
print(circuit.draw())
# Create a local simulator
simulator = AerSimulator()
# Run the circuit 1000 times (1000 shots)
job = simulator.run(circuit, shots=1000)
# Get the results
result = job.result()
counts = result.get_counts(circuit)
print("\nResults:")
print(counts)
You may need to install the Aer simulator separately:
pip install qiskit-aer
Output (your numbers will vary slightly):
Circuit:
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
Results:
{'00': 489, '11': 511}
The results show approximately equal counts for “00” and “11”, with no “01” or “10”. This confirms our circuit is working correctly.
Note: The local simulator is a classical computer pretending to be a quantum computer. It gives ideal results without the noise present in real quantum hardware.
Part 5: Running on Azure Quantum
Now let us run the same circuit on Azure Quantum.
Connecting to Your Workspace
Create a new file called bell_state_azure.py:
from qiskit import QuantumCircuit
from azure.quantum.qiskit import AzureQuantumProvider
# Connect to Azure Quantum
# Replace these with your actual values from the Azure portal
provider = AzureQuantumProvider(
resource_id="/subscriptions/YOUR-SUBSCRIPTION-ID/resourceGroups/YOUR-RESOURCE-GROUP/providers/Microsoft.Quantum/Workspaces/YOUR-WORKSPACE-NAME",
location="eastus"
)
# List available backends
print("Available backends:")
for backend in provider.backends():
print(f" - {backend.name()}")
Replace the resource_id and location with your actual values from the Azure portal.
Run this to verify your connection:
python bell_state_azure.py
You should see a list of backends like:
Available backends:
- ionq.simulator
- ionq.qpu.aria-1
- quantinuum.sim.h1-1e
- quantinuum.qpu.h1-1
- rigetti.sim.qvm
- microsoft.estimator
The backends ending in .simulator, .sim, or .qvm are simulators (free or low cost). The backends with .qpu are real quantum hardware (costs money per job).
Running on IonQ’s Simulator
from qiskit import QuantumCircuit
from azure.quantum.qiskit import AzureQuantumProvider
# Connect to Azure Quantum
provider = AzureQuantumProvider(
resource_id="/subscriptions/YOUR-SUBSCRIPTION-ID/resourceGroups/YOUR-RESOURCE-GROUP/providers/Microsoft.Quantum/Workspaces/YOUR-WORKSPACE-NAME",
location="eastus"
)
# Select the IonQ simulator backend
backend = provider.get_backend("ionq.simulator")
# Create the Bell state circuit
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])
print("Submitting job to IonQ simulator...")
# Submit the job
job = backend.run(circuit, shots=1000)
# Wait for the job to complete and get results
print(f"Job ID: {job.id()}")
print("Waiting for results...")
result = job.result()
counts = result.get_counts(circuit)
print("\nResults from IonQ simulator:")
print(counts)
The first run may take a minute while Azure authenticates you. A browser window may open asking you to log in to your Azure account.
Output:
Submitting job to IonQ simulator...
Job ID: 12345678-1234-1234-1234-123456789abc
Waiting for results...
Results from IonQ simulator:
{'00': 497, '11': 503}
Part 6: Understanding the Results
Reading the Output
The results come back as a dictionary where:
Keys are measurement outcomes as bit strings
Values are the number of times each outcome occurred
{'00': 497, '11': 503}
This means:
497 out of 1000 shots measured both qubits as 0
503 out of 1000 shots measured both qubits as 1
Bit String Order
Qiskit uses little-endian bit ordering by default. In the string “00”:
The rightmost bit is qubit 0
The leftmost bit is qubit 1
So “00” means qubit 0 = 0 and qubit 1 = 0.
This can be confusing when you have more qubits. For a 3-qubit measurement “101”:
Qubit 0 (rightmost) = 1
Qubit 1 (middle) = 0
Qubit 2 (leftmost) = 1
What Perfect Results Look Like
For an ideal Bell state:
“00”: 50%
“11”: 50%
“01”: 0%
“10”: 0%
Simulators give results close to this ideal. Real quantum hardware will show small percentages of “01” and “10” due to noise and errors in the physical qubits.
Results from Real Hardware
If you run on actual quantum hardware (e.g., ionq.qpu.aria-1), your results might look like:
{'00': 481, '11': 492, '01': 14, '10': 13}
The small counts of “01” and “10” are errors. Current quantum hardware is noisy, and qubits can lose their quantum state (decohere) or be affected by environmental interference. Error rates vary by hardware and improve over time as technology advances.
Part 7: Cost Considerations
Simulators
Cloud simulators are free or very low cost:
IonQ simulator: Free
Rigetti QVM: Free
Quantinuum emulators: Some usage included free
Use simulators for development and testing.
Real Quantum Hardware
Running on actual QPUs costs money. Pricing varies by provider:
IonQ charges per “gate-shot” (number of gates multiplied by number of shots). A simple circuit with 1000 shots might cost a few dollars.
Quantinuum uses “H-System Quantum Credits” (HQCs). They offer a small free allocation for testing.
Rigetti charges by execution time.
Check the Azure Quantum pricing page and your workspace’s Providers tab for current rates. Start with simulators and only move to real hardware when you need to test actual quantum behavior.
What You Have Learned
In this article, you:
Understood the software stack: Python/Qiskit code becomes OpenQASM, which Azure Quantum sends to hardware providers
Set up a local environment: Created a virtual environment and installed Qiskit with Azure support
Created an Azure Quantum workspace: Configured cloud access to quantum simulators and hardware
Built a quantum circuit: Used Hadamard and CNOT gates to create entanglement
Ran the circuit: First locally, then on Azure’s cloud simulators
Interpreted results: Understood measurement counts and verified entanglement
What Comes Next
In Part II of this series, we will:
Explore more quantum gates and build more complex circuits
Learn about quantum algorithms that solve real problems
Compare results across different hardware providers
Understand and measure quantum noise
Troubleshooting Common Issues
“ModuleNotFoundError: No module named ‘qiskit’”
Your virtual environment may not be activated. Run:
source quantum-env/bin/activate # Linux/Mac
quantum-env\Scripts\activate # Windows
“Authentication failed” when connecting to Azure
A browser window should open for authentication. If it does not, try:
az login
(Install Azure CLI first if needed: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)
“Backend not found”
Check that the provider is enabled in your workspace. Go to Azure portal, open your workspace, click “Providers”, and verify the provider is listed.
Results show unexpected outcomes
If running on real hardware, some errors are expected. Current quantum hardware has error rates of 0.1% to 1% per gate. For testing correctness, use simulators first.
Meiling Zhang writes about quantum computing. She is a partner and cofounder at machine61 and the founder at funded quantum computing startup focusing on applications in signal processing for the defense space. Meiling enjoys being a mother, and running obstacles courses and is an advanced crossfitter.
Salvatore Magnone is a father, veteran, and a co-founder, a repeat offender in the best way in fact. Sal builds successful, multinational, technology companies at machine61, and runs obstacle courses. He teaches business and military strategy at the university level and directly to entrepreneurs and military leaders.
Machine61 ( machine61 llc. ) is a leading advisory in computing, data, ai, quantum, and robotics across defense, insurance, legal, and manufacturing. See www.machine61.net for more information.
Disclaimer: The authors are long IONQ, RGTI, QBTS, QBUT, MSFT, and IBM.



