diff --git a/src/braket/experimental/autoqasm/api.py b/src/braket/experimental/autoqasm/api.py index e1eb36859..b6f421e3a 100644 --- a/src/braket/experimental/autoqasm/api.py +++ b/src/braket/experimental/autoqasm/api.py @@ -16,8 +16,9 @@ import copy import functools import inspect +from collections.abc import Callable from types import FunctionType -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from typing import Any, Optional, Union import openqasm3.ast as qasm_ast import oqpy.base @@ -120,15 +121,15 @@ def gate_calibration(*args, implements: Callable, **kwargs) -> Callable[[], Gate def _function_wrapper( - *args: Tuple[Any], + *args: tuple[Any], converter_callback: Callable, - converter_args: Optional[Dict[str, Any]] = None, + converter_args: Optional[dict[str, Any]] = None, ) -> Callable[[Any], aq_program.Program]: """Wrapping and conversion logic around the user function `f`. Args: converter_callback (Callable): The function converter, e.g., _convert_main. - converter_args (Optional[Dict[str, Any]]): Extra arguments for the function converter. + converter_args (Optional[dict[str, Any]]): Extra arguments for the function converter. Returns: Callable[[Any], Program]: A callable which returns the converted @@ -167,7 +168,7 @@ def _wrapper(*args, **kwargs) -> Callable: return autograph_artifact(decorated_wrapper) -def _autograph_optional_features() -> Tuple[converter.Feature]: +def _autograph_optional_features() -> tuple[converter.Feature]: # Exclude autograph features which are TensorFlow-specific return converter.Feature.all_but( (converter.Feature.NAME_SCOPES, converter.Feature.AUTO_CONTROL_DEPS) @@ -177,8 +178,8 @@ def _autograph_optional_features() -> Tuple[converter.Feature]: def _convert_main( f: Callable, options: converter.ConversionOptions, - args: List[Any], - kwargs: Dict[str, Any], + args: list[Any], + kwargs: dict[str, Any], user_config: aq_program.UserConfig, ) -> None: """Convert the initial callable `f` into a full AutoQASM program `program`. @@ -191,8 +192,8 @@ def _convert_main( Args: f (Callable): The function to be converted. options (converter.ConversionOptions): Converter options. - args (List[Any]): Arguments passed to the program when called. - kwargs (Dict[str, Any]): Keyword arguments passed to the program when called. + args (list[Any]): Arguments passed to the program when called. + kwargs (dict[str, Any]): Keyword arguments passed to the program when called. user_config (UserConfig): User-specified settings that influence program building. """ if aq_program.in_active_program_conversion_context(): @@ -260,8 +261,8 @@ def _add_qubit_declaration(program_conversion_context: aq_program.ProgramConvers def _convert_subroutine( f: Callable, options: converter.ConversionOptions, - args: List[Any], - kwargs: Dict[str, Any], + args: list[Any], + kwargs: dict[str, Any], ) -> None: """Convert the initial callable `f` into a full AutoQASM program `program`. The contents of `f` are converted into a subroutine in the program. @@ -272,8 +273,8 @@ def _convert_subroutine( Args: f (Callable): The function to be converted. options (converter.ConversionOptions): Converter options. - args (List[Any]): Arguments passed to the program when called. - kwargs (Dict[str, Any]): Keyword arguments passed to the program when called. + args (list[Any]): Arguments passed to the program when called. + kwargs (dict[str, Any]): Keyword arguments passed to the program when called. """ if not aq_program.in_active_program_conversion_context(): raise errors.AutoQasmTypeError( @@ -426,18 +427,7 @@ def _make_return_instance_from_f_annotation(f: Callable) -> Any: # TODO: Recursive functions should work even if the user's type hint is wrong annotations = f.__annotations__ return_type = annotations["return"] if "return" in annotations else None - - return_instance = None - if return_type and aq_types.is_qasm_type(return_type): - return_instance = return_type() - elif return_type: - if hasattr(return_type, "__origin__"): - # Types from python's typing module, such as `List`. origin gives us `list`` - return_instance = return_type.__origin__() - else: - return_instance = return_type() - - return return_instance + return return_type() if return_type else None def _make_return_instance_from_oqpy_return_type(return_type: Any) -> Any: @@ -461,8 +451,8 @@ def _get_bitvar_size(node: qasm_ast.BitType) -> Optional[int]: def _convert_gate( f: Callable, options: converter.ConversionOptions, - args: List[Any], - kwargs: Dict[str, Any], + args: list[Any], + kwargs: dict[str, Any], ) -> Callable: # We must be inside an active conversion context in order to invoke a gate program_conversion_context = aq_program.get_program_conversion_context() @@ -558,8 +548,8 @@ def _get_gate_args(f: Callable) -> aq_program.GateArgs: def _convert_calibration( f: Callable, options: converter.ConversionOptions, - args: List[Any], - kwargs: Dict[str, Any], + args: list[Any], + kwargs: dict[str, Any], gate_function: Callable, **decorator_kwargs, ) -> GateCalibration: @@ -569,8 +559,8 @@ def _convert_calibration( Args: f (Callable): The function to be converted. options (converter.ConversionOptions): Converter options. - args (List[Any]): Arguments passed to the program when called. - kwargs (Dict[str, Any]): Keyword arguments passed to the program when called. + args (list[Any]): Arguments passed to the program when called. + kwargs (dict[str, Any]): Keyword arguments passed to the program when called. gate_function (Callable): The gate function which calibration is being defined. Returns: @@ -624,14 +614,14 @@ def _convert_calibration( def _validate_calibration_args( gate_function: Callable, - decorator_args: Dict[str, Union[Qubit, float]], + decorator_args: dict[str, Union[Qubit, float]], func_args: aq_program.GateArgs, ) -> None: """Validate the arguments passed to the calibration decorator and function. Args: gate_function (Callable): The gate function which calibration is being defined. - decorator_args (Dict[str, Union[Qubit, float]]): The calibration decorator arguments. + decorator_args (dict[str, Union[Qubit, float]]): The calibration decorator arguments. func_args (aq_program.GateArgs): The gate function arguments. """ gate_args = _get_gate_args(gate_function) diff --git a/src/braket/experimental/autoqasm/instructions/instructions.py b/src/braket/experimental/autoqasm/instructions/instructions.py index 0e93f7974..24077b16c 100644 --- a/src/braket/experimental/autoqasm/instructions/instructions.py +++ b/src/braket/experimental/autoqasm/instructions/instructions.py @@ -15,7 +15,7 @@ """Non-unitary instructions that apply to qubits. """ -from typing import Any, List +from typing import Any from braket.experimental.autoqasm import program as aq_program @@ -23,7 +23,7 @@ def _qubit_instruction( - name: str, qubits: List[QubitIdentifierType], *args: Any, is_unitary: bool = True + name: str, qubits: list[QubitIdentifierType], *args: Any, is_unitary: bool = True ) -> None: program_conversion_context = aq_program.get_program_conversion_context() program_conversion_context.validate_gate_targets(qubits, args) diff --git a/src/braket/experimental/autoqasm/instructions/measurements.py b/src/braket/experimental/autoqasm/instructions/measurements.py index b747ed9f0..2b9fb98dc 100644 --- a/src/braket/experimental/autoqasm/instructions/measurements.py +++ b/src/braket/experimental/autoqasm/instructions/measurements.py @@ -23,25 +23,25 @@ def my_program(): """ -from typing import List, Union +from typing import Union from braket.experimental.autoqasm import program from braket.experimental.autoqasm import types as aq_types from braket.experimental.autoqasm.instructions.qubits import QubitIdentifierType, _qubit -def measure(qubits: Union[QubitIdentifierType, List[QubitIdentifierType]]) -> aq_types.BitVar: +def measure(qubits: Union[QubitIdentifierType, list[QubitIdentifierType]]) -> aq_types.BitVar: """Add qubit measurement statements to the program and assign the measurement results to bit variables. Args: - qubits (Union[QubitIdentifierType, List[QubitIdentifierType]]): The target qubits + qubits (Union[QubitIdentifierType, list[QubitIdentifierType]]): The target qubits to measure. Returns: BitVar: Bit variable the measurement results are assigned to. """ - if not isinstance(qubits, List): + if not isinstance(qubits, list): qubits = [qubits] oqpy_program = program.get_program_conversion_context().get_oqpy_program() diff --git a/src/braket/experimental/autoqasm/instructions/qubits.py b/src/braket/experimental/autoqasm/instructions/qubits.py index 7a33bc88c..507ba178e 100644 --- a/src/braket/experimental/autoqasm/instructions/qubits.py +++ b/src/braket/experimental/autoqasm/instructions/qubits.py @@ -16,7 +16,7 @@ import re from functools import singledispatch -from typing import Any, List, Union +from typing import Any, Union import oqpy.base from openpulse.printer import dumps @@ -38,14 +38,14 @@ def is_qubit_identifier_type(qubit: Any) -> bool: return isinstance(qubit, QubitIdentifierType.__args__) -def _get_physical_qubit_indices(qids: List[str]) -> List[int]: +def _get_physical_qubit_indices(qids: list[str]) -> list[int]: """Convert physical qubit labels to the corresponding qubit indices. Args: - qids (List[str]): Physical qubit labels. + qids (list[str]): Physical qubit labels. Returns: - List[int]: Qubit indices corresponding to the input physical qubits. + list[int]: Qubit indices corresponding to the input physical qubits. """ braket_qubits = [] for qid in qids: diff --git a/src/braket/experimental/autoqasm/operators/conditional_expressions.py b/src/braket/experimental/autoqasm/operators/conditional_expressions.py index 40b591f7f..94a9e0f2b 100644 --- a/src/braket/experimental/autoqasm/operators/conditional_expressions.py +++ b/src/braket/experimental/autoqasm/operators/conditional_expressions.py @@ -14,7 +14,8 @@ """Operators for conditional expressions (e.g. the ternary if statement).""" -from typing import Any, Callable, Optional +from collections.abc import Callable +from typing import Any, Optional import oqpy.base diff --git a/src/braket/experimental/autoqasm/operators/control_flow.py b/src/braket/experimental/autoqasm/operators/control_flow.py index 6ead0d574..33fb10965 100644 --- a/src/braket/experimental/autoqasm/operators/control_flow.py +++ b/src/braket/experimental/autoqasm/operators/control_flow.py @@ -14,7 +14,8 @@ """Operators for control flow constructs (e.g. if, for, while).""" -from typing import Any, Callable, Iterable, Optional, Union +from collections.abc import Callable, Iterable +from typing import Any, Optional, Union import oqpy.base diff --git a/src/braket/experimental/autoqasm/program/gate_calibrations.py b/src/braket/experimental/autoqasm/program/gate_calibrations.py index ad76dcd5e..75045f046 100644 --- a/src/braket/experimental/autoqasm/program/gate_calibrations.py +++ b/src/braket/experimental/autoqasm/program/gate_calibrations.py @@ -14,7 +14,7 @@ from __future__ import annotations -from typing import Callable, Iterable +from collections.abc import Callable, Iterable from braket.experimental.autoqasm.instructions.qubits import QubitIdentifierType as Qubit from braket.experimental.autoqasm.program import Program diff --git a/src/braket/experimental/autoqasm/program/program.py b/src/braket/experimental/autoqasm/program/program.py index 411cbcb69..b6eaed22e 100644 --- a/src/braket/experimental/autoqasm/program/program.py +++ b/src/braket/experimental/autoqasm/program/program.py @@ -16,9 +16,10 @@ import contextlib import threading +from collections.abc import Callable, Iterable from dataclasses import dataclass from enum import Enum -from typing import Any, Callable, Iterable, List, Optional, Union +from typing import Any, Optional, Union import oqpy.base @@ -99,12 +100,12 @@ def __init__( self._oqpy_program = oqpy_program self._has_pulse_control = has_pulse_control - def with_calibrations(self, gate_calibrations: Union[Callable, List[Callable]]) -> Program: + def with_calibrations(self, gate_calibrations: Union[Callable, list[Callable]]) -> Program: """Add the gate calibrations to the program. The calibration added program is returned as a new object. The original program is not modified. Args: - gate_calibrations (Union[Callable, List[Callable]]): The gate calibrations to add to + gate_calibrations (Union[Callable, list[Callable]]): The gate calibrations to add to the main program. Calibration are passed as callable without evaluation. Returns: @@ -156,7 +157,7 @@ class GateArgs: """Represents a list of qubit and angle arguments for a gate definition.""" def __init__(self): - self._args: List[Union[oqpy.Qubit, oqpy.AngleVar]] = [] + self._args: list[Union[oqpy.Qubit, oqpy.AngleVar]] = [] def __len__(self): return len(self._args) @@ -174,19 +175,19 @@ def append(self, name: str, is_qubit: bool) -> None: self._args.append(oqpy.AngleVar(name=name)) @property - def qubits(self) -> List[oqpy.Qubit]: + def qubits(self) -> list[oqpy.Qubit]: return [self._args[i] for i in self.qubit_indices] @property - def angles(self) -> List[oqpy.AngleVar]: + def angles(self) -> list[oqpy.AngleVar]: return [self._args[i] for i in self.angle_indices] @property - def qubit_indices(self) -> List[int]: + def qubit_indices(self) -> list[int]: return [i for i, arg in enumerate(self._args) if isinstance(arg, oqpy.Qubit)] @property - def angle_indices(self) -> List[int]: + def angle_indices(self) -> list[int]: return [i for i, arg in enumerate(self._args) if isinstance(arg, oqpy.AngleVar)] @@ -229,11 +230,11 @@ def make_program(self) -> Program: return Program(self.get_oqpy_program(), has_pulse_control=self._has_pulse_control) @property - def qubits(self) -> List[int]: + def qubits(self) -> list[int]: """Return a sorted list of virtual qubits used in this program. Returns: - List[int]: The list of virtual qubits, e.g. [0, 1, 2] + list[int]: The list of virtual qubits, e.g. [0, 1, 2] """ # Can be memoized or otherwise made more performant return sorted(list(self._virtual_qubits_used)) @@ -323,12 +324,12 @@ def is_var_name_used(self, var_name: str) -> bool: or var_name in oqpy_program.undeclared_vars.keys() ) - def validate_gate_targets(self, qubits: List[Any], angles: List[Any]) -> None: + def validate_gate_targets(self, qubits: list[Any], angles: list[Any]) -> None: """Validate that the specified gate targets are valid at this point in the program. Args: - qubits (List[Any]): The list of target qubits to validate. - angles (List[Any]): The list of target angles to validate. + qubits (list[Any]): The list of target qubits to validate. + angles (list[Any]): The list of target angles to validate. Raises: errors.InvalidTargetQubit: Target qubits are invalid in the current context. @@ -359,10 +360,10 @@ def validate_gate_targets(self, qubits: List[Any], angles: List[Any]) -> None: ) @staticmethod - def _normalize_gate_names(gate_names: Iterable[str]) -> List[str]: + def _normalize_gate_names(gate_names: Iterable[str]) -> list[str]: return [gate_name.lower() for gate_name in gate_names] - def _validate_verbatim_target_qubits(self, qubits: List[Any]) -> None: + def _validate_verbatim_target_qubits(self, qubits: list[Any]) -> None: # Only physical target qubits are allowed in a verbatim block: for qubit in qubits: if not isinstance(qubit, str): diff --git a/src/braket/experimental/autoqasm/pulse/pulse.py b/src/braket/experimental/autoqasm/pulse/pulse.py index e0581b1b3..c8c12741e 100644 --- a/src/braket/experimental/autoqasm/pulse/pulse.py +++ b/src/braket/experimental/autoqasm/pulse/pulse.py @@ -15,7 +15,7 @@ """Pulse instructions that apply to frames or qubits. """ -from typing import List, Union +from typing import Union import oqpy @@ -127,17 +127,17 @@ def capture_v0(frame: Frame) -> None: def delay( - qubits_or_frames: Union[Frame, List[Frame], QubitIdentifierType, List[QubitIdentifierType]], + qubits_or_frames: Union[Frame, list[Frame], QubitIdentifierType, list[QubitIdentifierType]], duration: Union[float, oqpy.FloatVar], ) -> None: """Adds an instruction to advance the frame clock by the specified `duration` value. Args: - qubits_or_frames (Union[Frame, List[Frame], QubitIdentifierType, List[QubitIdentifierType]]): + qubits_or_frames (Union[Frame, list[Frame], QubitIdentifierType, list[QubitIdentifierType]]): Qubits or frame(s) on which the delay needs to be introduced. duration (Union[float, FloatVar]): Value (in seconds) defining the duration of the delay. """ # noqa: E501 - if not isinstance(qubits_or_frames, List): + if not isinstance(qubits_or_frames, list): qubits_or_frames = [qubits_or_frames] if all(is_qubit_identifier_type(q) for q in qubits_or_frames): qubits_or_frames = QubitSet(_get_physical_qubit_indices(qubits_or_frames)) @@ -147,17 +147,17 @@ def delay( def barrier( - qubits_or_frames: Union[Frame, List[Frame], QubitIdentifierType, List[QubitIdentifierType]] + qubits_or_frames: Union[Frame, list[Frame], QubitIdentifierType, list[QubitIdentifierType]] ) -> None: """Adds an instruction to align the frame clocks to the latest time across all the specified frames. When applied on qubits, it prevents compilations across the barrier, if the compiler supports barrier. Args: - qubits_or_frames (Union[Frame, List[Frame], QubitIdentifierType, List[QubitIdentifierType]]): + qubits_or_frames (Union[Frame, list[Frame], QubitIdentifierType, list[QubitIdentifierType]]): Qubits or frame(s) on which the barrier needs to be introduced. """ # noqa: E501 - if not isinstance(qubits_or_frames, List): + if not isinstance(qubits_or_frames, list): qubits_or_frames = [qubits_or_frames] if all(is_qubit_identifier_type(q) for q in qubits_or_frames): qubits_or_frames = QubitSet(_get_physical_qubit_indices(qubits_or_frames)) diff --git a/src/braket/experimental/autoqasm/transpiler/transpiler.py b/src/braket/experimental/autoqasm/transpiler/transpiler.py index b2e4f33b4..2dc0dbfc8 100644 --- a/src/braket/experimental/autoqasm/transpiler/transpiler.py +++ b/src/braket/experimental/autoqasm/transpiler/transpiler.py @@ -21,7 +21,8 @@ import functools import importlib import inspect -from typing import Any, Callable, Optional, Tuple, Union +from collections.abc import Callable +from typing import Any, Optional, Union import gast @@ -261,7 +262,7 @@ def _converted_partial( ) -def _inspect_callable(f: Callable, args: tuple) -> Tuple[Callable, tuple]: +def _inspect_callable(f: Callable, args: tuple) -> tuple[Callable, tuple]: target_entity = None effective_args = None @@ -281,7 +282,7 @@ def _try_convert_actual( effective_args: tuple, kwargs: dict, options: converter.ConversionOptions, -) -> Tuple[Callable, Optional[Exception]]: +) -> tuple[Callable, Optional[Exception]]: converted_f = None exc = None try: diff --git a/src/braket/experimental/autoqasm/types/types.py b/src/braket/experimental/autoqasm/types/types.py index 27b2467f0..2bf8627de 100644 --- a/src/braket/experimental/autoqasm/types/types.py +++ b/src/braket/experimental/autoqasm/types/types.py @@ -32,13 +32,10 @@ def is_qasm_type(val: Any) -> bool: Returns: bool: Whether the object is a QASM type. """ - try: - if issubclass(val, (oqpy.Range, oqpy._ClassicalVar, oqpy.base.OQPyExpression)): - return True - except TypeError: - # `val` is not a class - pass - + # The input can either be a class, like oqpy.Range ... + if type(val) is type: + return issubclass(val, (oqpy.Range, oqpy._ClassicalVar, oqpy.base.OQPyExpression)) + # ... or an instance of a class, like oqpy.Range(10) return isinstance(val, (oqpy.Range, oqpy._ClassicalVar, oqpy.base.OQPyExpression)) diff --git a/test/unit_tests/braket/experimental/autoqasm/conftest.py b/test/unit_tests/braket/experimental/autoqasm/conftest.py index 417d8dd22..beaa53d46 100644 --- a/test/unit_tests/braket/experimental/autoqasm/conftest.py +++ b/test/unit_tests/braket/experimental/autoqasm/conftest.py @@ -13,7 +13,7 @@ """Test fixtures shared among the tests.""" -from typing import Callable +from collections.abc import Callable import pytest diff --git a/test/unit_tests/braket/experimental/autoqasm/mock_transpiler.py b/test/unit_tests/braket/experimental/autoqasm/mock_transpiler.py index 75166c9d7..fa53451a3 100644 --- a/test/unit_tests/braket/experimental/autoqasm/mock_transpiler.py +++ b/test/unit_tests/braket/experimental/autoqasm/mock_transpiler.py @@ -13,7 +13,7 @@ """Mock transpiler for testing converters.""" -from typing import List, Union +from typing import Union import gast @@ -24,11 +24,11 @@ class MockTranspiler(PyToOqpy): - def __init__(self, converters: List): + def __init__(self, converters: list): """A custom transpiler based on `transpiler.PyToOqpy` for unit testing converters. Args: - converters (List): List of converters to test. + converters (list): List of converters to test. """ super(MockTranspiler, self).__init__() if isinstance(converters, (list, tuple)): diff --git a/test/unit_tests/braket/experimental/autoqasm/test_operators.py b/test/unit_tests/braket/experimental/autoqasm/test_operators.py index ac438f999..7d144743b 100644 --- a/test/unit_tests/braket/experimental/autoqasm/test_operators.py +++ b/test/unit_tests/braket/experimental/autoqasm/test_operators.py @@ -13,7 +13,8 @@ """Tests for the operators module.""" -from typing import Any, Callable +from collections.abc import Callable +from typing import Any import oqpy.base import pytest diff --git a/test/unit_tests/braket/experimental/autoqasm/test_types.py b/test/unit_tests/braket/experimental/autoqasm/test_types.py index c5b975773..b214720fd 100644 --- a/test/unit_tests/braket/experimental/autoqasm/test_types.py +++ b/test/unit_tests/braket/experimental/autoqasm/test_types.py @@ -13,8 +13,6 @@ """Tests for the types module.""" -from typing import List, Tuple - import oqpy import pytest @@ -30,13 +28,13 @@ ], ) def test_qasm_range( - range_params: Tuple[int, int, int], expected_range_params: Tuple[int, int, int] + range_params: tuple[int, int, int], expected_range_params: tuple[int, int, int] ) -> None: """Test `qasm_range()` returning correct `Range` object. Args: - range_params (Tuple[int, int, int]): Range parameters to instantiate `oqpy.Range` - expected_range_params (Tuple[int, int, int]): Expected range parameters + range_params (tuple[int, int, int]): Range parameters to instantiate `oqpy.Range` + expected_range_params (tuple[int, int, int]): Expected range parameters """ start, stop, step = range_params qrange = qasm_range(start, stop, step) @@ -183,12 +181,12 @@ def test_return_array_int(): """Test return type discovery of array values.""" @aq.subroutine - def ret_test() -> List[int]: + def ret_test() -> list[int]: res = aq.ArrayVar([1, 2, 3], dimensions=[3]) return res @aq.main - def main() -> List[int]: + def main() -> list[int]: return ret_test() expected = """OPENQASM 3.0; @@ -207,7 +205,7 @@ def test_return_python_array(): """Test returning a python array of ints.""" @aq.subroutine - def tester() -> List[int]: + def tester() -> list[int]: return [1, 2, 3] @aq.main(num_qubits=4) @@ -230,7 +228,7 @@ def test_return_array_unsupported(): """Test unsupported array type.""" @aq.subroutine - def tester(arr: List[float]) -> List[float]: + def tester(arr: list[float]) -> list[float]: return [1.2, 2.1] @aq.main(num_qubits=4) @@ -326,7 +324,7 @@ def test_map_array(): """Test array input parameter type.""" @aq.subroutine - def annotation_test(input: List[int]): + def annotation_test(input: list[int]): pass @aq.main @@ -551,7 +549,7 @@ def test_recursive_list() -> None: """Tests recursive subroutines which return a list.""" @aq.subroutine - def retval_recursive() -> List[int]: + def retval_recursive() -> list[int]: retval_recursive() return [1] @@ -581,7 +579,7 @@ def test_error_for_tuple_param() -> None: """Tuples are not supported as parameters.""" @aq.subroutine - def param_test(input: Tuple): + def param_test(input: tuple): pass @aq.main @@ -611,7 +609,7 @@ def test_ignore_ret_typehint_bool(): """Test type discovery of boolean return values.""" @aq.subroutine - def ret_test() -> List[int]: + def ret_test() -> list[int]: return True @aq.main @@ -706,7 +704,7 @@ def test_param_array_list_missing_arg(): """Test list parameter with missing type arg (list rather than list[int]).""" @aq.subroutine - def param_test(arr: List) -> int: + def param_test(arr: list) -> int: return 1 @aq.main(num_qubits=4)