# Copyright 2026 qBraid
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=line-too-long
# Portions of this module are adapted from microsoft/qiskit-qir
# (https://github.com/microsoft/qiskit-qir), with modifications by qBraid.
# The original MIT license notice is reproduced in NOTICE.md.
# pylint: enable=line-too-long
"""
Module defining Qiskit circuit elements for QIR conversion.
"""
from abc import ABCMeta, abstractmethod
from typing import TYPE_CHECKING, Optional, Union
from pyqir import Module
from qiskit import ClassicalRegister, QuantumRegister
from qiskit.circuit import Clbit, Qubit
from qiskit.circuit.quantumcircuit import QuantumCircuit
if TYPE_CHECKING:
from qiskit.circuit.instruction import Instruction
class _QuantumCircuitElement(metaclass=ABCMeta):
"""Abstract base class for quantum circuit elements."""
@classmethod
def from_element_list(cls, elements):
"""Create a list of circuit elements from a list of raw elements."""
return [cls(elem) for elem in elements]
@abstractmethod
def accept(self, visitor):
"""Accept a visitor to process this element."""
class _Register(_QuantumCircuitElement):
"""Wrapper for a Qiskit register element."""
def __init__(self, register: Union[QuantumRegister, ClassicalRegister]):
self._register: Union[QuantumRegister, ClassicalRegister] = register
def accept(self, visitor):
"""Accept a visitor to process this register."""
visitor.visit_register(self._register)
class _Instruction(_QuantumCircuitElement):
"""Wrapper for a Qiskit instruction element."""
@classmethod
def from_element_list(cls, elements):
raise NotImplementedError(
"_Instruction requires (instruction, qargs, cargs); use direct construction."
)
def __init__(
self,
instruction: "Instruction",
qargs: tuple[Qubit, ...],
cargs: tuple[Clbit, ...],
):
self._instruction: "Instruction" = instruction
self._qargs = qargs
self._cargs = cargs
def accept(self, visitor):
"""Accept a visitor to process this instruction."""
visitor.visit_instruction(self._instruction, self._qargs, self._cargs)
def generate_module_id(circuit: QuantumCircuit) -> str:
"""Generate a unique module ID for a circuit."""
return circuit.name if circuit.name else "main"
[docs]
class QiskitModule:
"""Represents a Qiskit quantum circuit prepared for QIR conversion.
Attributes:
circuit: The original Qiskit QuantumCircuit.
name: The name of the module.
module: The PyQIR Module being built.
num_qubits: Number of qubits in the circuit.
num_clbits: Number of classical bits in the circuit.
reg_sizes: List of sizes for each classical register.
"""
[docs]
def __init__( # pylint: disable=too-many-arguments
self,
circuit: QuantumCircuit,
name: str,
module: Optional[Module],
num_qubits: int,
num_clbits: int,
reg_sizes: list[int],
elements: list[_QuantumCircuitElement],
):
self._circuit = circuit
self._name = name
self._module = module
self._elements = elements
self._num_qubits = num_qubits
self._num_clbits = num_clbits
self.reg_sizes = reg_sizes
@property
def circuit(self) -> QuantumCircuit:
"""Return the underlying Qiskit circuit."""
return self._circuit
@property
def name(self) -> str:
"""Return the module name."""
return self._name
@property
def module(self) -> Optional[Module]:
"""Return the PyQIR module."""
return self._module
@property
def num_qubits(self) -> int:
"""Return the number of qubits."""
return self._num_qubits
@property
def num_clbits(self) -> int:
"""Return the number of classical bits."""
return self._num_clbits
@classmethod
def from_circuit(
cls, circuit: QuantumCircuit, module: Optional[Module] = None
) -> "QiskitModule":
"""Create a new QiskitModule from a Qiskit QuantumCircuit.
Args:
circuit: The Qiskit QuantumCircuit to convert.
module: An optional existing PyQIR Module to use.
Returns:
A new QiskitModule instance.
"""
elements: list[_QuantumCircuitElement] = []
reg_sizes = [len(creg) for creg in circuit.cregs]
# Add registers
elements.extend(_Register.from_element_list(circuit.qregs))
elements.extend(_Register.from_element_list(circuit.cregs))
# Add instructions (updated for qiskit 2.x)
for circuit_instruction in circuit.data:
instruction = circuit_instruction.operation
qargs = circuit_instruction.qubits
cargs = circuit_instruction.clbits
elements.append(_Instruction(instruction, qargs, cargs))
name = generate_module_id(circuit)
return cls(
circuit=circuit,
name=name,
module=module,
num_qubits=circuit.num_qubits,
num_clbits=circuit.num_clbits,
reg_sizes=reg_sizes,
elements=elements,
)
def accept(self, visitor):
"""Accept a visitor to process this module.
Args:
visitor: The visitor to accept.
"""
visitor.visit_qiskit_module(self)
for element in self._elements:
element.accept(visitor)
visitor.record_output()
visitor.finalize()