• Tetra Quark

On this page

  • Introduction
    • Installation and Setup
      • Step 1: Install Qiskit and Qiskit Aer
      • Step 2: Configure Python Path for R/reticulate
      • Step 3: Verify Installation
      • Important Changes in Qiskit 2.x
    • Quantum Gates
  • Let the code begin
  • Simulation with Qiskit Aer
  • Measurement

Getting Started with Qiskit

  • Show All Code
  • Hide All Code
Quantum Computation
Published

June 26, 2025

Abstract
This tutorial provides a comprehensive introduction to getting started with quantum computing using Qiskit, IBM’s open-source quantum computing framework. We demonstrate the complete workflow from installation and setup to implementing quantum circuits. The tutorial walks through creating a three-qubit Greenberger-Horne-Zeilinger (GHZ) entangled state using fundamental quantum gates including Hadamard and controlled-NOT operations. Using Qiskit Aer’s simulation backends, we visualize quantum states, perform measurements, and analyze statistical outcomes with confidence intervals.
Keywords

Qiskit, Quantum Computation

\(\require{cancel}\)

Introduction

Qiskit is a Python-based, open-source framework for quantum computing. It supports superconducting qubits and trapped ions as physical implementations. The qiskit library is available at GitHub [1]. This post is a detailed exploration of one of the examples [2] included the qiskit tutorials. All the credit for the code belongs to the qiskit team, and I made only small changes. If you would like to run the original code online, I pulled it into a binder page [3].

Installation and Setup

Note: This setup was tested on macOS with Apple Silicon (M1/M2 chips) using conda environment.

Step 1: Install Qiskit and Qiskit Aer

In Qiskit 2.x, the simulator backend (Aer) has been moved to a separate package. You need to install both:

Code
conda install -c conda-forge qiskit qiskit-aer -y

Alternatively, you can use pip, but conda is recommended for Apple Silicon Macs:

Code
pip install qiskit qiskit-aer

Step 2: Configure Python Path for R/reticulate

If you’re using R with reticulate (as in this document), you need to set the correct Python path:

Code
# Set Python path to your conda installation
Sys.setenv(RETICULATE_PYTHON="/opt/anaconda3/bin/python")

To find your Python path, run in terminal:

Code
which python3
# or
python3 -c "import sys; print(sys.executable)"

Step 3: Verify Installation

Test that everything works:

Code
import qiskit
from qiskit_aer import Aer
print(f"Qiskit version: {qiskit.__version__}")
Qiskit version: 2.1.0
Code
print(f"Available backends: {Aer.backends()}")
Available backends: [AerSimulator('aer_simulator'), AerSimulator('aer_simulator_statevector'), AerSimulator('aer_simulator_density_matrix'), AerSimulator('aer_simulator_stabilizer'), AerSimulator('aer_simulator_matrix_product_state'), AerSimulator('aer_simulator_extended_stabilizer'), AerSimulator('aer_simulator_unitary'), AerSimulator('aer_simulator_superop'), QasmSimulator('qasm_simulator'), StatevectorSimulator('statevector_simulator'), UnitarySimulator('unitary_simulator')]

Important Changes in Qiskit 2.x

  • Aer import: Use from qiskit_aer import Aer instead of from qiskit import Aer
  • Circuit execution: Use backend.run(circuit) instead of execute(circuit, backend)
  • Circuit composition: Use circuit1.compose(circuit2) instead of circuit1 + circuit2

Once you have the library properly installed, you can start playing with the code.

Quantum Gates

Any quantum algorithm will involve single qubit and multi qubit operations. This introduction code, for example, has a Hadamard-Walsh gate, which transforms \(|0\rangle\) to \(\frac{|0\rangle+|1\rangle}{\sqrt{2}}\). There will be other operations that act on two qubits at once, such as the controlled-not (CNOT) gate. We will start from a state \(|\psi\rangle_f\) which is a tensor product of \(3\) independent states, initialized at \(|0\rangle\), i.e.: \[\begin{equation} |\psi\rangle_i=|000\rangle \label{eq:psi0}. \end{equation}\] After a set of gate operations, we will arrive at a three-qubit GHZ state, which is given by \[\begin{equation} |\psi\rangle_f=\frac{|000\rangle+|111\rangle}{\sqrt{2}} \label{eq:psi1}. \end{equation}\]

We can then simulate the circuit and make measurements on the outputs. The physical implementation of the qubits and the measulrement is beyond the scope of this post, however, I already have a post on superconducting qubits which might be a good read.

Let the code begin

We load the library and initiate a quantum system of \(3\) qubits.

Code
import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_aer import Aer


circ = QuantumCircuit(3) # Create a Quantum Circuit acting on a quantum register of three qubits

The sequence of operations is as follows:

  1. A Hadamard gate on qubit \(0\),
  2. A controlled-Not operation (\(C_{X}\)) between qubit \(0\) and qubit \(1\), and
  3. A controlled-Not operation between qubit \(0\) and qubit \(2\), as implemented in the code snippet below.
Code
# Build the quantum circuit
gates = [
    circ.h(0),     # Add a H gate on qubit 0, putting this qubit in superposition.
    circ.cx(0, 1), # Add a CX (CNOT) gate on control qubit 0 and target qubit 1, putting the qubits in a Bell state.
    circ.cx(0, 2)  # Add a CX (CNOT) gate on control qubit 0 and target qubit 2, putting the qubits in a GHZ state.
]


circ.draw('mpl', style=circuit_style) # draw the circuit with custom styling
Figure 1: The quantum circuit to create the GHZ state.

Qiskit has a specific way of ordering qubits in the state representation. For example, if qubit zero is in state \(0\), qubit \(1\) is in state \(0\), and qubit \(2\) is in state \(1\), Qiskit would represent this state as \(|100\rangle\), compared to typical physics textbook representation of \(|001\rangle\). In this representation, the controlled-not operator, with qubit \(0\) being the control and qubit \(1\) being the target, reads: \[\begin{equation} C_X = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\\end{pmatrix} \label{eq:cnot}. \end{equation}\]

Simulation with Qiskit Aer

Qiskit Aer is the quantum circuits simulating package. It provides various backends for simulations. We will use statevector_simulator. It computes and returns the quantum state. Note that the dimensionality of the state grows exponentially: with \(n\) qubits the result is a complex vector of dimension \(2^n\).

Code
# Import Aer (already imported above)
backend = Aer.get_backend('statevector_simulator') # Run the quantum circuit on a statevector simulator backend
job = backend.run(circ)# Create a Quantum Program for execution
result = job.result()# Create a Quantum Program for execution

The result object contains the data and Qiskit provides the method result.get_statevector(circ) to return the state vector for the quantum circuit.

Code
outputstate = result.get_statevector(circ, decimals=3)
print(outputstate)
Statevector([0.707+0.j, 0.   +0.j, 0.   +0.j, 0.   +0.j, 0.   +0.j,
             0.   +0.j, 0.   +0.j, 0.707+0.j],
            dims=(2, 2, 2))

The visualization function can be used to plot the real and imaginary components of the state density matrix \(\rho\), which is defined as: \[\begin{equation} \rho\equiv |\psi\rangle\langle\psi|=\frac{|000\rangle\langle 000|+|000\rangle\langle 111|+|000\rangle\langle 000|+|111\rangle\langle 111| }{2} \label{eq:rho}. \end{equation}\]

Code
from qiskit.visualization import plot_state_city
plot_state_city(outputstate)
Figure 2: The real and imaginary components of the density matrix. Note that the coefficients are in agreement with the state \(\rho\) as defined in Eq. \(\ref{eq:rho}\).

Measurement

To simulate a circuit that includes measurement, we add measurements to the original circuit above, and use a different Aer backend.

Code

# Add classical registers to the original circuit for measurement
qc = QuantumCircuit(3, 3)  # 3 qubits, 3 classical bits
gates = [qc.h(0), qc.cx(0, 1), qc.cx(0, 2), qc.barrier(range(3)), qc.measure(range(3), range(3))]

The measurement collapses the quantum states onto classical bits. and they are stored in classical registers,

The measurement can be simulated in qasm_simulator. The shots parameter sets the number of simulations.

Code
backend_sim = Aer.get_backend('qasm_simulator')# Use Aer's qasm_simulator
nshots=1024
job_sim = backend_sim.run(qc, shots=nshots)# Execute the circuit on the qasm simulator.
result_sim = job_sim.result()# Grab the results from the job.

get_counts(circuit) returns aggregated binary outcomes of the simulated circuit

Code
counts = result_sim.get_counts(qc)
p=counts['000']/nshots
print(counts)
{'111': 517, '000': 507}

plot_histogram can be used to plot the distribution of the outcomes.

Code
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Figure 3: The histogram of the outcomes.

From the output numbers, one can see that 49.5% of the time, we get the classical output \(000\). However, it is always a good practice to compute and include the confidence intervals, say \(95\%\). For a binary random variable, the confidence intervals are given by

\[\begin{equation} \hat p\pm z\sqrt{\frac{\hat p(1-\hat p)}{n_\text{trials}}} \label{eq:cconf}. \end{equation}\] where \(\hat p\) is the observed value of the probability and \(z\) is the z-score for the confidence level (i.e., \(1.96\) for \(95\%\)).

Code
delta=1.96*np.sqrt(p*(1-p)/nshots)
pmin=p-delta
pmax=p+delta

Therefore, the simulations with \(1024\) trials show that the probability of measuring state \(000\) is \([ 0.46 , 0.53 ]\) with \(95\%\) confidence.

\(\nextSection\)

References

[1]
H. Abraham et al., “Qiskit: An open-source framework for quantum computing.” 2019 [Online]. Available: https://github.com/Qiskit/qiskit
[2]
T. I. et al, “Qiskit tutorials.” 2019 [Online]. Available: https://github.com/Qiskit/qiskit-tutorials
[3]
T. I. et al, “Getting started with qiskit.” 2021 [Online]. Available: https://hub-binder.mybinder.ovh/user/quarktetra-qiskit-77ywlcgh/notebooks/circuits/1_getting_started_with_qiskit.ipynb