Hamiltonians and Time Evolution#
MIMIQ provides tools to define quantum Hamiltonians and simulate their time evolution using Trotterization methods. This page explains how to construct Hamiltonians, compute their expectation values, and apply Lie-Trotter, Suzuki-Trotter, and Yoshida decompositions.
This workflow allows you to:
Build realistic Hamiltonians from Pauli terms
Simulate time evolution efficiently using Trotter expansions
Measure physical observables like energy
Contents#
Hamiltonian#
In quantum computing, Hamiltonians play a central role in algorithms such as the Variational Quantum Eigensolver (VQE), Quantum Phase Estimation, and the Quantum Approximate Optimization Algorithm (QAOA). They are used to encode the energy landscape of a physical system, generate dynamics, or define cost functions for optimization.
A typical Hamiltonian is expressed as a sum of weighted Pauli strings:
Each term consists of a real coefficient \(c_j\) and a Pauli string \(P_j\), such as X
, ZZ
, or XYZ
,
which acts on a specific subset of qubits.
In quantum circuit frameworks, these Hamiltonians are often represented programmatically by associating each Pauli string with a set of target qubit indices and a coefficient, allowing users to construct and simulate physical models or optimization problems.
Simulating the Ising Model#
A fundamental use case for Hamiltonians in quantum computing is to estimate physical quantities like the ground state energy of a system. This is at the heart of quantum algorithms such as the Variational Quantum Eigensolver (VQE), quantum simulation of materials, and quantum optimization.
Here, we demonstrate how to use MIMIQ to:
Build the Hamiltonian for the 1D transverse-field Ising model
Apply Trotterized time evolution (first and second order)
Measure the energy (expectation value of the Hamiltonian)
This provides a concrete template for simulating many-body quantum systems.
Ising Model#
The 1D transverse-field Ising model is defined by the Hamiltonian:
This models a chain of spins with:
nearest-neighbor interaction (ZZ terms),
and a transverse magnetic field (X terms).
It’s widely used in condensed matter physics and quantum algorithm benchmarks.
Building the Hamiltonian#
To construct this model in MIMIQ you can use Hamiltonian
class to easily build your hamiltonian:
>>> N = 4 # number of qubits (spins)
>>> J = 1.0 # interaction strength
>>> h = 0.5 # field strength
>>> hamiltonian = Hamiltonian()
>>> for j in range(N - 1):
... _ = hamiltonian.push(-J, PauliString("ZZ"), j, j + 1)
>>> for j in range(N):
... _ = hamiltonian.push(-h, PauliString("X"), j)
>>> print(hamiltonian)
4-qubit Hamiltonian with 7 terms:
├── -1.0 * ZZ @ q[0,1]
├── -1.0 * ZZ @ q[1,2]
├── -1.0 * ZZ @ q[2,3]
├── -0.5 * X @ q[0]
├── -0.5 * X @ q[1]
├── -0.5 * X @ q[2]
└── -0.5 * X @ q[3]
Simulating Time Evolution#
Suppose we want to apply \(e^{-iHt}\) to a quantum state. This is useful for preparing ground states via imaginary-time evolution (approximate cooling), or evolving an initial state in real time.
Because H has non-commuting terms, we use a Trotter approximation.
First-order Trotterization (Lie) (push_lietrotter()
)
>>> c = Circuit()
>>> c.push_lietrotter(hamiltonian, tuple(range(N)), t = 0.1, steps = 1)
4-qubit circuit with 1 instructions:
└── trotter(0.1) @ q[0,1,2,3]
>>> c.decompose()
4-qubit circuit with 7 instructions:
├── RZZ(-0.2) @ q[0,1]
├── RZZ(-0.2) @ q[1,2]
├── RZZ(-0.2) @ q[2,3]
├── RX(-0.1) @ q[0]
├── RX(-0.1) @ q[1]
├── RX(-0.1) @ q[2]
└── RX(-0.1) @ q[3]
Second-order Trotterization (Suzuki) (push_suzukitrotter()
)
>>> c = Circuit()
>>> c.push_suzukitrotter(hamiltonian, tuple(range(N)), t = 0.1, steps = 1, order = 2)
4-qubit circuit with 1 instructions:
└── suzukitrotter_2(0.1) @ q[0,1,2,3]
>>> c.decompose()
4-qubit circuit with 14 instructions:
├── RZZ(-0.1) @ q[0,1]
├── RZZ(-0.1) @ q[1,2]
├── RZZ(-0.1) @ q[2,3]
├── RX(-0.05) @ q[0]
├── RX(-0.05) @ q[1]
├── RX(-0.05) @ q[2]
├── RX(-0.05) @ q[3]
├── RX(-0.05) @ q[3]
├── RX(-0.05) @ q[2]
├── RX(-0.05) @ q[1]
├── RX(-0.05) @ q[0]
├── RZZ(-0.1) @ q[2,3]
├── RZZ(-0.1) @ q[1,2]
└── RZZ(-0.1) @ q[0,1]
Measuring the Energy#
Once the circuit has prepared the desired quantum state such as by applying time evolution with Trotterization we can measure the energy
by evaluating the expectation value (push_expval()
) of the Hamiltonian.
>>> c.push_expval(hamiltonian, *range(N))
4-qubit, 7-zvar circuit with 16 instructions:
├── suzukitrotter_2(0.1) @ q[0,1,2,3]
├── ⟨ZZ⟩ @ q[0,1], z[0]
├── z[0] *= -1.0
├── ⟨ZZ⟩ @ q[1,2], z[1]
├── z[1] *= -1.0
├── ⟨ZZ⟩ @ q[2,3], z[2]
├── z[2] *= -1.0
├── ⟨X⟩ @ q[0], z[3]
├── z[3] *= -0.5
├── ⟨X⟩ @ q[1], z[4]
├── z[4] *= -0.5
├── ⟨X⟩ @ q[2], z[5]
├── z[5] *= -0.5
├── ⟨X⟩ @ q[3], z[6]
├── z[6] *= -0.5
└── z[0] += 0.0 + z[1] + z[2] + z[3] + z[4] + z[5] + z[6]
The result is stored in the Z-register — the first index contains the total expectation value (energy). You can access it from the simulation result.