Skip to content

circuit_builder

CircuitBuilder

A class using the builder pattern to make construction of circuits easy from Python. Adds corresponding instruction when a method is called. Checks that instructions are known and called with the right arguments. Mainly here to allow for Qiskit-style circuit construction:

Parameters:

Name Type Description Default
qubit_register_size int

Size of the qubit register

0
bit_register_size int

Size of the bit register

0
Example

>>> CircuitBuilder(qubit_register_size=3, bit_register_size=3).H(0).CNOT(0, 1).CNOT(0, 2).to_circuit()
version 3.0

qubit[3] q

h q[0]
cnot q[0], q[1]
cnot q[0], q[2]

Source code in opensquirrel/circuit_builder.py
class CircuitBuilder:
    """
    A class using the builder pattern to make construction of circuits easy from Python.
    Adds corresponding instruction when a method is called. Checks that instructions are known and
    called with the right arguments.
    Mainly here to allow for Qiskit-style circuit construction:

    Args:
        qubit_register_size (int): Size of the qubit register
        bit_register_size (int): Size of the bit register

    Example:
        ```python
        >>> CircuitBuilder(qubit_register_size=3, bit_register_size=3).H(0).CNOT(0, 1).CNOT(0, 2).to_circuit()
        ```
        ```
        version 3.0

        qubit[3] q

        h q[0]
        cnot q[0], q[1]
        cnot q[0], q[2]

        ```
    """

    def __init__(
        self,
        qubit_register_size: int = 0,
        bit_register_size: int = 0,
    ) -> None:
        initial_qubit_registry = (
            OrderedDict({DEFAULT_QUBIT_REGISTER_NAME: QubitRegister(qubit_register_size)})
            if (qubit_register_size > 0)
            else OrderedDict()
        )
        initial_bit_registry = (
            OrderedDict({DEFAULT_BIT_REGISTER_NAME: BitRegister(bit_register_size)})
            if (bit_register_size > 0)
            else OrderedDict()
        )
        self.register_manager = RegisterManager(
            initial_qubit_registry,
            initial_bit_registry,
        )
        self.ir = IR()

    def __dir__(self) -> list[str]:
        return super().__dir__() + list(_builder_dynamic_attributes)  # type: ignore

    def __getattr__(self, attr: str) -> Any:
        if attr in _builder_dynamic_attributes:
            return partial(self._add_statement, attr)
        # Default behaviour
        return self.__getattribute__(attr)

    def add_register(self, register: QubitRegister | BitRegister) -> None:
        """Add a (qu)bit register to the circuit builder.

        Args:
            register (QubitRegister | BitRegister): (Qu)bit register to add.

        """
        self.register_manager.add_register(register)

    def _check_qubit_out_of_bounds_access(self, qubit: QubitLike) -> None:
        """Throw error if qubit index is outside the qubit register range.

        Args:
            qubit: qubit to check.
        """
        index = Qubit(qubit).index
        qubit_register_size = self.register_manager.qubit_register_size
        if index >= qubit_register_size:
            msg = f"qubit index {index!r} is out of bounds: must be smaller than {qubit_register_size!r}"
            raise IndexError(msg)

    def _check_bit_out_of_bounds_access(self, bit: BitLike) -> None:
        """Throw error if bit index is outside the bit register range.

        Args:
            bit: bit to check.
        """
        index = Bit(bit).index
        bit_register_size = self.register_manager.bit_register_size
        if index >= bit_register_size:
            msg = f"bit index {index!r} is out of bounds: must be smaller than {bit_register_size!r}"
            raise IndexError(msg)

    def _check_out_of_bounds_access(self, instruction: Instruction) -> None:
        for qubit in instruction.qubit_operands:
            self._check_qubit_out_of_bounds_access(qubit)

        for bit in instruction.bit_operands:
            self._check_bit_out_of_bounds_access(bit)

    def _add_statement(self, attr: str, *args: Any) -> Self:
        if attr == "asm":
            try:
                asm_declaration = AsmDeclaration(*args)
                self.ir.add_asm_declaration(asm_declaration)
            except TypeError:
                msg = f"trying to build {attr!r} with the wrong number or type of arguments: {args!r}"
                raise TypeError(msg) from None
            return self

        if attr not in default_instruction_set:
            msg = f"unknown instruction {attr!r}"
            raise ValueError(msg)
        try:
            instruction = default_instruction_set[attr](*args)
        except TypeError as e:
            msg = f"trying to build {attr!r} with the wrong number or type of arguments: {args!r}: {e}"
            raise TypeError(msg) from e

        self._check_out_of_bounds_access(instruction)

        self.ir.add_statement(instruction)
        return self

    def to_circuit(self) -> Circuit:
        """Build the circuit.

        Returns:
            Circuit: The built circuit.

        """
        return Circuit(deepcopy(self.register_manager), deepcopy(self.ir))

add_register

add_register(register: QubitRegister | BitRegister) -> None

Add a (qu)bit register to the circuit builder.

Parameters:

Name Type Description Default
register QubitRegister | BitRegister

(Qu)bit register to add.

required
Source code in opensquirrel/circuit_builder.py
def add_register(self, register: QubitRegister | BitRegister) -> None:
    """Add a (qu)bit register to the circuit builder.

    Args:
        register (QubitRegister | BitRegister): (Qu)bit register to add.

    """
    self.register_manager.add_register(register)

to_circuit

to_circuit() -> Circuit

Build the circuit.

Returns:

Name Type Description
Circuit Circuit

The built circuit.

Source code in opensquirrel/circuit_builder.py
def to_circuit(self) -> Circuit:
    """Build the circuit.

    Returns:
        Circuit: The built circuit.

    """
    return Circuit(deepcopy(self.register_manager), deepcopy(self.ir))