From 93deb42c2745b902b3190a5014f964e045638322 Mon Sep 17 00:00:00 2001 From: Noa Aarts Date: Wed, 18 Mar 2026 10:22:44 +0100 Subject: [PATCH] pqc to qiskit conversion --- src/quantum_circuit/__init__.py | 17 ++++++++ src/quantum_circuit/qiskit_helpers.py | 58 ++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/quantum_circuit/__init__.py b/src/quantum_circuit/__init__.py index 62f185f..f9b6c15 100644 --- a/src/quantum_circuit/__init__.py +++ b/src/quantum_circuit/__init__.py @@ -39,6 +39,17 @@ class QuantumType(enum.Enum): QuantumType.RZ, } + def is_parameterized(self): + return self in { + QuantumType.RX, + QuantumType.RXX, + QuantumType.RY, + QuantumType.RYY, + QuantumType.RZ, + QuantumType.RZZ, + QuantumType.CRX, + } + @dataclass(frozen=True) class QuantumGate: @@ -59,6 +70,9 @@ class ParametrizedQuantumCircuit: gates: list[list[QuantumGate]] """Gates in the quantum circuit, organised as a list of layers of gates.""" + parameters: int + """How many parameters are used the circuit""" + _expressivity: float | None = None """ Expressivity of the circuit, following the definition from {THE PAPER} @@ -90,6 +104,9 @@ class ParametrizedQuantumCircuit: """ Add a layer to the end of the existing circuit in-place """ + for gate in layer: + if gate.type.is_parameterized(): + self.parameters += 1 self.gates.append(layer) @property diff --git a/src/quantum_circuit/qiskit_helpers.py b/src/quantum_circuit/qiskit_helpers.py index 3daceff..a9476bc 100644 --- a/src/quantum_circuit/qiskit_helpers.py +++ b/src/quantum_circuit/qiskit_helpers.py @@ -1,11 +1,65 @@ from typing import TYPE_CHECKING from qiskit import QuantumCircuit +from qiskit.circuit.parameter import Parameter from qiskit.circuit.parametervector import ParameterVector if TYPE_CHECKING: - from quantum_circuit import ParametrizedQuantumCircuit + from quantum_circuit import (ParametrizedQuantumCircuit, QuantumGate, + QuantumType) + + +def add_qubit_gate(circ: QuantumCircuit, gate: QuantumGate, theta: Parameter) -> int: + match gate.type: + case QuantumType.Identity: + return 0 + case QuantumType.Hadamard: + circ.h(gate.qubits[0]) + return 0 + case QuantumType.X: + circ.x(gate.qubits[0]) + return 0 + case QuantumType.RX: + circ.rx(theta, gate.qubits[0]) + return 1 + case QuantumType.RXX: + circ.rxx(theta, gate.qubits[0], gate.qubits[1]) # ty:ignore[index-out-of-bounds] + return 1 + case QuantumType.Y: + circ.y(gate.qubits[0]) + return 0 + case QuantumType.RY: + circ.ry(theta, gate.qubits[0]) + return 1 + case QuantumType.RYY: + circ.ryy(theta, gate.qubits[0], gate.qubits[1]) # ty:ignore[index-out-of-bounds] + return 1 + case QuantumType.Z: + circ.z(gate.qubits[0]) + return 0 + case QuantumType.RZ: + circ.rz(theta, gate.qubits[0]) + return 1 + case QuantumType.RZZ: + circ.rzz(theta, gate.qubits[0], gate.qubits[1]) # ty:ignore[index-out-of-bounds] + return 1 + case QuantumType.CRX: + circ.crx(theta, gate.qubits[0], gate.qubits[1]) # ty:ignore[index-out-of-bounds] + return 1 + case QuantumType.CX: + circ.cx(gate.qubits[0], gate.qubits[1]) # ty:ignore[index-out-of-bounds] + return 0 + raise NotImplementedError def build_qiskit_circ(pqc: "ParametrizedQuantumCircuit") -> tuple[QuantumCircuit, ParameterVector]: - raise NotImplementedError + + circ = QuantumCircuit(pqc.qubits) + thetas = ParameterVector("thetas", circ.parameters) + + current_theta_index = 0 + for layer in pqc.gates: + for gate in layer: + current_theta_index += add_qubit_gate(circ, gate, thetas[current_theta_index]) + + return circ, thetas