|
| 1 | +# Copyright (c) 2023 - 2025 Chair for Design Automation, TUM |
| 2 | +# Copyright (c) 2025 Munich Quantum Software Company GmbH |
| 3 | +# All rights reserved. |
| 4 | +# |
| 5 | +# SPDX-License-Identifier: MIT |
| 6 | +# |
| 7 | +# Licensed under the MIT License |
| 8 | + |
| 9 | +"""HHL Benchmark Circuit Generation.""" |
| 10 | + |
| 11 | +from __future__ import annotations |
| 12 | + |
| 13 | +import numpy as np |
| 14 | +from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister |
| 15 | +from qiskit.circuit.library import QFTGate |
| 16 | + |
| 17 | + |
| 18 | +def create_circuit(num_qubits: int) -> QuantumCircuit: |
| 19 | + """HHL algorithm for a fixed 2x2 Hermitian matrix A using scalable QPE precision. |
| 20 | +
|
| 21 | + This implementation simulates a more accurate model of the HHL algorithm |
| 22 | + for the matrix A = [[1, 1], [1, 3]] with known eigenvalues. |
| 23 | +
|
| 24 | + Args: |
| 25 | + num_qubits: Number of qubits in the phase estimation register (precision control) |
| 26 | +
|
| 27 | + Returns: |
| 28 | + QuantumCircuit: Qiskit circuit implementing HHL |
| 29 | + """ |
| 30 | + assert num_qubits >= 3, "Number of qubits must be at least 3 for HHL." |
| 31 | + num_qpe_qubits = num_qubits - 2 |
| 32 | + qr_sys = QuantumRegister(1, name="sys") # System qubit (|b⟩) |
| 33 | + qr_eig = QuantumRegister(num_qpe_qubits, name="phase") # Eigenvalue estimation |
| 34 | + qr_anc = QuantumRegister(1, name="ancilla") # Ancilla for rotation |
| 35 | + cr = ClassicalRegister(1, name="c") # Classical for system measurement |
| 36 | + qc = QuantumCircuit(qr_sys, qr_eig, qr_anc, cr) |
| 37 | + |
| 38 | + # Step 1: Prepare |b⟩ = |1⟩ |
| 39 | + qc.x(qr_sys[0]) |
| 40 | + |
| 41 | + # Step 2: Apply Hadamards to phase register (QPE start) |
| 42 | + qc.h(qr_eig) |
| 43 | + |
| 44 | + # Step 3: Controlled-unitary approximation simulating controlled-e^{iAt} |
| 45 | + # A = [[1, 1], [1, 3]], eigenvalues: lam1 ≈ 0.382, lam2 ≈ 3.618 |
| 46 | + # We simulate one eigenvalue's evolution as approximation |
| 47 | + t = 2 * np.pi |
| 48 | + lam = 3.618 # simulate dominant eigenvalue for better realism |
| 49 | + |
| 50 | + for j in range(num_qpe_qubits): |
| 51 | + angle = t * lam / (2 ** (j + 1)) |
| 52 | + qc.cp(angle, qr_eig[j], qr_sys[0]) |
| 53 | + |
| 54 | + # Step 4: Apply inverse QFT |
| 55 | + qc.append(QFTGate(num_qpe_qubits).inverse(), qr_eig) |
| 56 | + |
| 57 | + # Step 5: Controlled Ry rotations on ancilla (based on actual eigenvalue) |
| 58 | + for j in range(num_qpe_qubits): |
| 59 | + # Approximate eigenvalue encoded in basis state |j⟩ |
| 60 | + # Use inverse λ (scaled appropriately) |
| 61 | + estimated_lambda = lam / (2 ** (num_qpe_qubits - j)) |
| 62 | + if estimated_lambda > 0: |
| 63 | + inv_lambda = 1.0 / estimated_lambda |
| 64 | + inv_lambda = np.clip(inv_lambda, -1, 1) # valid for arcsin |
| 65 | + theta = 2 * np.arcsin(inv_lambda) |
| 66 | + qc.cry(theta, qr_eig[j], qr_anc[0]) |
| 67 | + |
| 68 | + # Step 6: QPE uncomputation (apply QFT + reverse controlled unitary) |
| 69 | + qc.append(QFTGate(num_qpe_qubits), qr_eig) |
| 70 | + for j in reversed(range(num_qpe_qubits)): |
| 71 | + angle = -t * lam / (2 ** (j + 1)) |
| 72 | + qc.cp(angle, qr_eig[j], qr_sys[0]) |
| 73 | + |
| 74 | + # Step 7: Final Hadamards and measurement |
| 75 | + qc.h(qr_eig) |
| 76 | + qc.measure(qr_sys[0], cr[0]) |
| 77 | + qc.name = "hhl" |
| 78 | + return qc |
0 commit comments