Source code for mqt.bench.benchmarks.hhl
# Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
# Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
# All rights reserved.
#
# SPDX-License-Identifier: MIT
#
# Licensed under the MIT License
"""HHL Benchmark Circuit Generation."""
from __future__ import annotations
import numpy as np
from qiskit.circuit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.circuit.library import QFTGate
from ._registry import register_benchmark
[docs]
@register_benchmark("hhl", description="Harrow-Hassidim-Lloyd Algorithm (HHL)")
def create_circuit(num_qubits: int) -> QuantumCircuit:
"""HHL algorithm for a fixed 2x2 Hermitian matrix A using scalable QPE precision.
This implementation simulates a more accurate model of the HHL algorithm
for the matrix A = [[1, 1], [1, 3]] with known eigenvalues.
Args:
num_qubits: Total number of qubits (1 system + phase-estimation register + 1 ancilla). Must be at least 3.
Returns:
QuantumCircuit: Qiskit circuit implementing HHL
"""
if num_qubits < 3:
msg = "Number of qubits must be at least 3 for HHL."
raise ValueError(msg)
num_qpe_qubits = num_qubits - 2
qr_sys = QuantumRegister(1, name="sys") # System qubit (|b⟩)
qr_eig = QuantumRegister(num_qpe_qubits, name="phase") # Eigenvalue estimation
qr_anc = QuantumRegister(1, name="ancilla") # Ancilla for rotation
cr = ClassicalRegister(1, name="c") # Classical for system measurement
qc = QuantumCircuit(qr_sys, qr_eig, qr_anc, cr)
# Step 1: Prepare |b⟩ = |1⟩
qc.x(qr_sys[0])
# Step 2: Apply Hadamards to phase register (QPE start)
qc.h(qr_eig)
# Step 3: Controlled-unitary approximation simulating controlled-e^{iAt}
# A = [[1, 1], [1, 3]], eigenvalues: lam1 ≈ 0.382, lam2 ≈ 3.618
# We simulate one eigenvalue's evolution as approximation
t = 2 * np.pi
lam = 3.618 # simulate dominant eigenvalue for better realism
for j in range(num_qpe_qubits):
angle = t * lam / (2 ** (j + 1))
qc.cp(angle, qr_eig[j], qr_sys[0])
# Step 4: Apply inverse QFT
qc.append(QFTGate(num_qpe_qubits).inverse(), qr_eig)
# Step 5: Controlled Ry rotations on ancilla (based on actual eigenvalue)
for j in range(num_qpe_qubits):
# Approximate eigenvalue encoded in basis state |j⟩
# Use inverse λ (scaled appropriately)
estimated_lambda = lam / (2 ** (num_qpe_qubits - j))
if estimated_lambda > 0:
inv_lambda = 1.0 / estimated_lambda
inv_lambda = np.clip(inv_lambda, -1, 1) # valid for arcsin
theta = 2 * np.arcsin(inv_lambda)
qc.cry(theta, qr_eig[j], qr_anc[0])
# Step 6: QPE uncomputation (apply QFT + reverse controlled unitary)
qc.append(QFTGate(num_qpe_qubits), qr_eig)
for j in reversed(range(num_qpe_qubits)):
angle = -t * lam / (2 ** (j + 1))
qc.cp(angle, qr_eig[j], qr_sys[0])
# Step 7: Final Hadamards and measurement
qc.h(qr_eig)
qc.measure(qr_sys[0], cr[0])
qc.name = "hhl"
return qc