Transverse-Field Ising Model with Q-CTRL's Performance Management
Disse Sied is noch nich översett. Se kiekt de engelsche Originalversion an.
Usage estimate: 2 minutes on a Heron r2 processor. (NOTE: This is an estimate only. Your runtime may vary.)
Background
The Transverse-Field Ising Model (TFIM) is important for studying quantum magnetism and phase transitions. It describes a set of spins arranged on a lattice, where each spin interacts with its neighbors while also being influenced by an external magnetic field that drives quantum fluctuations.
A common approach to simulate this model is to use Trotter decomposition to approximate the time evolution operator, constructing circuits that alternate between single-qubit rotations and entangling two-qubit interactions. However, this simulation on real hardware is challenging due to noise and decoherence, leading to deviations from the true dynamics. To overcome this, we use Q-CTRL's Fire Opal error suppression and performance management tools, offered as a Qiskit Function (see the Fire Opal documentation). Fire Opal automatically optimizes circuit execution by applying dynamical decoupling, advanced layout, routing, and other error suppression techniques, all aimed at reducing noise. With these improvements, the hardware results align more closely with noiseless simulations, and thus we can study TFIM magnetization dynamics with higher fidelity.
In this tutorial we will:
- Build the TFIM Hamiltonian on a graph of connected spin triangles
- Simulate time evolution with Trotterized circuits at different depths
- Compute and visualize single-qubit magnetizations over time
- Compare baseline simulations with results from hardware runs using Q-CTRL's Fire Opal performance management
Overview
The Transverse-field Ising Model (TFIM) is a quantum spin model that captures essential features of quantum phase transitions. The Hamiltonian is defined as:
where and are Pauli operators acting on qubit , is the coupling strength between neighboring spins, and is the strength of the transverse magnetic field. The first term represents classical ferromagnetic interactions, while the second introduces quantum fluctuations through the transverse field. To simulate TFIM dynamics, you use a Trotter decomposition of the unitary evolution operator , implemented through layers of RX and RZZ gates based on a custom graph of connected spin triangles. The simulation explores how magnetization evolves with increasing Trotter steps.
The performance of the proposed TFIM implementation is assessed by comparing noiseless simulations with noisy backends. Fire Opal's enhanced execution and error suppression features are used to mitigate the effect of noise in real hardware, yielding more reliable estimates of spin observables like and correlators .
Requirements
Before starting this tutorial, be sure you have the following installed:
- Qiskit SDK v1.4 or later, with visualization support
- Qiskit Runtime v0.40 or later (
pip install qiskit-ibm-runtime) - Qiskit Functions Catalog v0.9.0 (
pip install qiskit-ibm-catalog) - Fire Opal SDK v9.0.2 or later (
pip install fire-opal) - Q-CTRL Visualizer v8.0.2 or later (
pip install qctrl-visualizer)
Setup
First, authenticate using your IBM Quantum API key. Then, select the Qiskit Function as follows. (This code assumes you've already saved your account to your local environment.)
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib networkx numpy qctrlvisualizer qiskit qiskit-aer qiskit-ibm-catalog qiskit-ibm-runtime
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit import QuantumCircuit
from qiskit_ibm_catalog import QiskitFunctionsCatalog
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import SamplerV2 as Sampler
from qiskit.quantum_info import SparsePauliOp
from qiskit_aer import AerSimulator
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import qctrlvisualizer as qv
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Access Function
perf_mgmt = catalog.load("q-ctrl/performance-management")
Step 1: Map classical inputs to a quantum problem
Generate TFIM graph
We begin by defining the lattice of spins and the couplings between them. In this tutorial, the lattice is constructed from connected triangles arranged in a linear chain. Each triangle consists of three nodes connected in a closed loop, and the chain is formed by linking one node of each triangle to the previous triangle.
The helper function connected_triangles_adj_matrix builds the adjacency matrix for this structure. For a chain of triangles, the resulting graph contains nodes.
def connected_triangles_adj_matrix(n):
"""
Generate the adjacency matrix for 'n' connected triangles in a chain.
"""
num_nodes = 2 * n + 1
adj_matrix = np.zeros((num_nodes, num_nodes), dtype=int)
for i in range(n):
a, b, c = i * 2, i * 2 + 1, i * 2 + 2 # Nodes of the current triangle
# Connect the three nodes in a triangle
adj_matrix[a, b] = adj_matrix[b, a] = 1
adj_matrix[b, c] = adj_matrix[c, b] = 1
adj_matrix[a, c] = adj_matrix[c, a] = 1
# If not the first triangle, connect to the previous triangle
if i > 0:
adj_matrix[a, a - 1] = adj_matrix[a - 1, a] = 1
return adj_matrix
To visualize the lattice we just defined, we can plot the chain of connected triangles and label each node. The function below builds the graph for a chosen number of triangles and displays it.
def plot_triangle_chain(n, side=1.0):
"""
Plot a horizontal chain of n equilateral triangles.
Baseline: even nodes (0,2,4,...,2n) on y=0
Apexes: odd nodes (1,3,5,...,2n-1) above the midpoint.
"""
# Build graph
A = connected_triangles_adj_matrix(n)
G = nx.from_numpy_array(A)
h = np.sqrt(3) / 2 * side
pos = {}
# Place baseline nodes
for k in range(n + 1):
pos[2 * k] = (k * side, 0.0)
# Place apex nodes
for k in range(n):
x_left = pos[2 * k][0]
x_right = pos[2 * k + 2][0]
pos[2 * k + 1] = ((x_left + x_right) / 2, h)
# Draw
fig, ax = plt.subplots(figsize=(1.5 * n, 2.5))
nx.draw(
G,
pos,
ax=ax,
with_labels=True,
font_size=10,
font_color="white",
node_size=600,
node_color=qv.QCTRL_STYLE_COLORS[0],
edge_color="black",
width=2,
)
ax.set_aspect("equal")
ax.margins(0.2)
plt.show()
return G, pos
For this tutorial we will use a chain of 20 triangles.
n_triangles = 20
n_qubits = 2 * n_triangles + 1
plot_triangle_chain(n_triangles, side=1.0)
plt.show()

Coloring graph edges
To implement the spin–spin coupling, it is useful to group edges that do not overlap. This allows us to apply two-qubit gates in parallel. We can do this with a simple edge-coloring procedure [1], which assigns a color to each edge so that edges meeting at the same node are placed in different groups.
def edge_coloring(graph):
"""
Takes a NetworkX graph and returns a list of lists where each inner list contains
the edges assigned the same color.
"""
line_graph = nx.line_graph(graph)
edge_colors = nx.coloring.greedy_color(line_graph)
color_groups = {}
for edge, color in edge_colors.items():
if color not in color_groups:
color_groups[color] = []
color_groups[color].append(edge)
return list(color_groups.values())
Step 2: Optimize problem for quantum hardware execution
Generate Trotterized circuits on spin graphs
To simulate the dynamics of the TFIM, we construct circuits that approximate the time evolution operator.
We use a second-order Trotter decomposition:
where and .
- The term is implemented with layers of
RXrotations. - The