From 751d84176374590bacce41530818eaa9c5a60512 Mon Sep 17 00:00:00 2001 From: TheGupta2012 Date: Fri, 11 Apr 2025 14:05:03 +0530 Subject: [PATCH 1/2] replace union with | --- src/pyqasm/analyzer.py | 4 +- src/pyqasm/elements.py | 6 +-- src/pyqasm/maps/expressions.py | 16 +++---- src/pyqasm/maps/gates.py | 76 +++++++++++++++++----------------- src/pyqasm/modules/qasm2.py | 5 +-- src/pyqasm/subroutines.py | 6 +-- src/pyqasm/transformer.py | 18 ++++---- src/pyqasm/validator.py | 6 +-- src/pyqasm/visitor.py | 16 +++---- 9 files changed, 76 insertions(+), 77 deletions(-) diff --git a/src/pyqasm/analyzer.py b/src/pyqasm/analyzer.py index 9e143058..3ce6ff72 100644 --- a/src/pyqasm/analyzer.py +++ b/src/pyqasm/analyzer.py @@ -19,7 +19,7 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any, Optional import numpy as np from openqasm3.ast import ( @@ -144,7 +144,7 @@ def _validate_step(start_id, end_id, step, span): @staticmethod def analyze_index_expression( index_expr: IndexExpression, - ) -> tuple[str, list[Union[Any, Expression, RangeDefinition]]]: + ) -> tuple[str, list[Any | Expression | RangeDefinition]]: """Analyze an index expression to get the variable name and indices. Args: diff --git a/src/pyqasm/elements.py b/src/pyqasm/elements.py index 28cfa544..6f9ebda7 100644 --- a/src/pyqasm/elements.py +++ b/src/pyqasm/elements.py @@ -18,7 +18,7 @@ """ from dataclasses import dataclass from enum import Enum -from typing import Any, Optional, Union +from typing import Any, Optional import numpy as np @@ -88,7 +88,7 @@ class Variable: # pylint: disable=too-many-instance-attributes base_type (Any): Base type of the variable. base_size (int): Base size of the variable. dims (Optional[List[int]]): Dimensions of the variable. - value (Optional[Union[int, float, np.ndarray]]): Value of the variable. + value (Optional[int | float | np.ndarray]): Value of the variable. is_constant (bool): Flag indicating if the variable is constant. is_register (bool): Flag indicating if the variable is a register. readonly (bool): Flag indicating if the variable is readonly. @@ -98,7 +98,7 @@ class Variable: # pylint: disable=too-many-instance-attributes base_type: Any base_size: int dims: Optional[list[int]] = None - value: Optional[Union[int, float, np.ndarray]] = None + value: Optional[int | float | np.ndarray] = None is_constant: bool = False is_register: bool = False readonly: bool = False diff --git a/src/pyqasm/maps/expressions.py b/src/pyqasm/maps/expressions.py index 4a1633da..0f19b072 100644 --- a/src/pyqasm/maps/expressions.py +++ b/src/pyqasm/maps/expressions.py @@ -17,7 +17,7 @@ """ -from typing import Callable, Union +from typing import Callable import numpy as np from openqasm3.ast import AngleType, BitType, BoolType, ComplexType, FloatType, IntType, UintType @@ -25,10 +25,10 @@ from pyqasm.exceptions import ValidationError # Define the type for the operator functions -OperatorFunction = Union[ - Callable[[Union[int, float, bool]], Union[int, float, bool]], - Callable[[Union[int, float, bool], Union[int, float, bool]], Union[int, float, bool]], -] +OperatorFunction = ( + Callable[[int | float | bool], int | float | bool] + | Callable[[int | float | bool, int | float | bool], int | float | bool] +) OPERATOR_MAP: dict[str, OperatorFunction] = { @@ -56,18 +56,18 @@ } -def qasm3_expression_op_map(op_name: str, *args) -> Union[float, int, bool]: +def qasm3_expression_op_map(op_name: str, *args) -> float | int | bool: """ Return the result of applying the given operator to the given operands. Args: op_name (str): The operator name. - *args: The operands of type Union[int, float, bool] + *args: The operands of type int | float | bool 1. For unary operators, a single operand (e.g., ~3) 2. For binary operators, two operands (e.g., 3 + 2) Returns: - (Union[float, int, bool]): The result of applying the operator to the operands. + (float | int | bool): The result of applying the operator to the operands. """ try: operator = OPERATOR_MAP[op_name] diff --git a/src/pyqasm/maps/gates.py b/src/pyqasm/maps/gates.py index de3ee055..1de2da80 100644 --- a/src/pyqasm/maps/gates.py +++ b/src/pyqasm/maps/gates.py @@ -20,7 +20,7 @@ """ -from typing import Callable, Union +from typing import Callable import numpy as np from openqasm3.ast import FloatLiteral, Identifier, IndexedIdentifier, QuantumGate, QuantumPhase @@ -32,9 +32,9 @@ def u3_gate( - theta: Union[int, float], - phi: Union[int, float], - lam: Union[int, float], + theta: int | float, + phi: int | float, + lam: int | float, qubit_id, ) -> list[QuantumGate]: """ @@ -44,9 +44,9 @@ def u3_gate( Args: name (str): The name of the gate. - theta (Union[int, float]): The theta parameter. - phi (Union[int, float]): The phi parameter. - lam (Union[int, float]): The lambda parameter. + theta (int | float): The theta parameter. + phi (int | float): The phi parameter. + lam (int | float): The lambda parameter. qubit_id (IndexedIdentifier): The qubit on which to apply the gate. Returns: @@ -63,9 +63,9 @@ def u3_gate( def u3_inv_gate( - theta: Union[int, float], - phi: Union[int, float], - lam: Union[int, float], + theta: int | float, + phi: int | float, + lam: int | float, qubits, ) -> list[QuantumGate]: """ @@ -165,7 +165,7 @@ def ch_gate(qubit0: IndexedIdentifier, qubit1: IndexedIdentifier) -> list[Quantu def xy_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """Implements the XXPlusYY gate matrix as defined by braket. @@ -177,8 +177,8 @@ def xy_gate( def xx_plus_yy_gate( - theta: Union[int, float], - phi: Union[int, float], + theta: int | float, + phi: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier, ) -> list[QuantumGate]: @@ -224,7 +224,7 @@ def xx_plus_yy_gate( def ryy_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the YY gate as a decomposition of other gates. @@ -260,7 +260,7 @@ def ryy_gate( def zz_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the ZZ gate as a decomposition of other gates. @@ -274,7 +274,7 @@ def zz_gate( return result -def phaseshift_gate(theta: Union[int, float], qubit: IndexedIdentifier) -> list[QuantumGate]: +def phaseshift_gate(theta: int | float, qubit: IndexedIdentifier) -> list[QuantumGate]: """ Implements the phase shift gate as a decomposition of other gates. """ @@ -313,7 +313,7 @@ def cswap_gate( def pswap_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the PSWAP gate as a decomposition of other gates. @@ -345,7 +345,7 @@ def iswap_gate(qubit0: IndexedIdentifier, qubit1: IndexedIdentifier) -> list[Qua def crx_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the CRX gate as a decomposition of other gates. @@ -378,7 +378,7 @@ def crx_gate( def cry_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the CRY gate as a decomposition of other gates. @@ -410,7 +410,7 @@ def cry_gate( def crz_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the CRZ gate as a decomposition of other gates. @@ -443,10 +443,10 @@ def crz_gate( def cu_gate( # pylint: disable=too-many-arguments - theta: Union[int, float], - phi: Union[int, float], - lam: Union[int, float], - gamma: Union[int, float], + theta: int | float, + phi: int | float, + lam: int | float, + gamma: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier, ) -> list[QuantumGate]: @@ -489,9 +489,9 @@ def cu_gate( # pylint: disable=too-many-arguments def cu3_gate( # pylint: disable=too-many-arguments - theta: Union[int, float], - phi: Union[int, float], - lam: Union[int, float], + theta: int | float, + phi: int | float, + lam: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier, ) -> list[QuantumGate]: @@ -528,7 +528,7 @@ def cu3_gate( # pylint: disable=too-many-arguments def cu1_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the CU1 gate as a decomposition of other gates. @@ -600,13 +600,13 @@ def csx_gate(qubit0: IndexedIdentifier, qubit1: IndexedIdentifier) -> list[Quant def rxx_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier -) -> list[Union[QuantumGate, QuantumPhase]]: + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier +) -> list[QuantumGate | QuantumPhase]: """ Implements the RXX gate as a decomposition of other gates. """ - result: list[Union[QuantumGate, QuantumPhase]] = [] + result: list[QuantumGate | QuantumPhase] = [] result.extend(global_phase_gate(-theta / 2, [qubit0, qubit1])) result.extend(one_qubit_gate_op("h", qubit0)) result.extend(one_qubit_gate_op("h", qubit1)) @@ -637,8 +637,8 @@ def rccx_gate( def rzz_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier -) -> list[Union[QuantumGate, QuantumPhase]]: + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier +) -> list[QuantumGate | QuantumPhase]: """ Implements the RZZ gate as a decomposition of other gates. @@ -661,7 +661,7 @@ def rzz_gate( q_1: ┤ X ├┤ U3(0,0,theta) ├┤ X ├ └───┘└───────────────┘└───┘ """ - result: list[Union[QuantumGate, QuantumPhase]] = [] + result: list[QuantumGate | QuantumPhase] = [] result.extend(global_phase_gate(-theta / 2, [qubit0, qubit1])) result.extend(two_qubit_gate_op("cx", qubit0, qubit1)) @@ -672,7 +672,7 @@ def rzz_gate( def cphaseshift_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the controlled phase shift gate as a decomposition of other gates. @@ -706,7 +706,7 @@ def cphaseshift_gate( def cphaseshift00_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the controlled phase shift 00 gate as a decomposition of other gates. @@ -725,7 +725,7 @@ def cphaseshift00_gate( def cphaseshift01_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the controlled phase shift 01 gate as a decomposition of other gates. @@ -742,7 +742,7 @@ def cphaseshift01_gate( def cphaseshift10_gate( - theta: Union[int, float], qubit0: IndexedIdentifier, qubit1: IndexedIdentifier + theta: int | float, qubit0: IndexedIdentifier, qubit1: IndexedIdentifier ) -> list[QuantumGate]: """ Implements the controlled phase shift 10 gate as a decomposition of other gates. diff --git a/src/pyqasm/modules/qasm2.py b/src/pyqasm/modules/qasm2.py index 5538d45f..f4b0de9d 100644 --- a/src/pyqasm/modules/qasm2.py +++ b/src/pyqasm/modules/qasm2.py @@ -18,7 +18,6 @@ import re from copy import deepcopy -from typing import Union import openqasm3.ast as qasm3_ast from openqasm3.ast import Include, Program @@ -78,7 +77,7 @@ def _qasm_ast_to_str(self, qasm_ast): raw_qasm = dumps(qasm_ast, old_measurement=True) return self._format_declarations(raw_qasm) - def to_qasm3(self, as_str: bool = False) -> Union[str, Qasm3Module]: + def to_qasm3(self, as_str: bool = False) -> str | Qasm3Module: """Convert the module to openqasm3 format Args: @@ -87,7 +86,7 @@ def to_qasm3(self, as_str: bool = False) -> Union[str, Qasm3Module]: Default is False. Returns: - Union[str, Qasm3Module]: The module in openqasm3 format. + str | Qasm3Module: The module in openqasm3 format. """ qasm_program = deepcopy(self._original_program) # replace the include with stdgates.inc diff --git a/src/pyqasm/subroutines.py b/src/pyqasm/subroutines.py index a3ee32f4..34e0f54f 100644 --- a/src/pyqasm/subroutines.py +++ b/src/pyqasm/subroutines.py @@ -16,7 +16,7 @@ Module containing the class for validating QASM3 subroutines. """ -from typing import Optional, Union +from typing import Optional from openqasm3.ast import ( AccessControl, @@ -50,11 +50,11 @@ def set_visitor_obj(cls, visitor_obj) -> None: cls.visitor_obj = visitor_obj @staticmethod - def get_fn_actual_arg_name(actual_arg: Union[Identifier, IndexExpression]) -> Optional[str]: + def get_fn_actual_arg_name(actual_arg: Identifier | IndexExpression) -> Optional[str]: """Get the name of the actual argument passed to a function. Args: - actual_arg (Union[Identifier, IndexExpression]): The actual argument passed to the + actual_arg (Identifier | IndexExpression): The actual argument passed to the function. Returns: diff --git a/src/pyqasm/transformer.py b/src/pyqasm/transformer.py index 36395e2c..039dbaa0 100644 --- a/src/pyqasm/transformer.py +++ b/src/pyqasm/transformer.py @@ -17,7 +17,7 @@ """ from copy import deepcopy -from typing import Any, NamedTuple, Optional, Union +from typing import Any, NamedTuple, Optional import numpy as np from openqasm3.ast import ( @@ -57,8 +57,8 @@ [ ("reg_idx", Optional[int]), ("reg_name", str), - ("op", Optional[Union[BinaryOperator, UnaryOperator]]), - ("rhs_val", Optional[Union[bool, int]]), + ("op", Optional[BinaryOperator | UnaryOperator]), + ("rhs_val", Optional[bool | int]), ], ) @@ -150,7 +150,7 @@ def get_qubits_from_range_definition( @staticmethod def transform_gate_qubits( - gate_op: Union[QuantumGate, QuantumPhase], qubit_map: dict[str, IndexedIdentifier] + gate_op: QuantumGate | QuantumPhase, qubit_map: dict[str, IndexedIdentifier] ) -> None: """Transform the qubits of a gate operation with a qubit map. @@ -175,7 +175,7 @@ def transform_gate_qubits( gate_op.qubits[i] = qubit_map[gate_qubit_name] @staticmethod - def transform_expression(expression, variable_map: dict[str, Union[int, float, bool]]): + def transform_expression(expression, variable_map: dict[str, int | float | bool]): """Transform an expression by replacing variables with their values. Args: @@ -215,13 +215,13 @@ def transform_expression(expression, variable_map: dict[str, Union[int, float, b @staticmethod def transform_gate_params( - gate_op: Union[QuantumGate, QuantumPhase], param_map: dict[str, Union[int, float, bool]] + gate_op: QuantumGate | QuantumPhase, param_map: dict[str, int | float | bool] ) -> None: """Transform the parameters of a gate operation with a parameter map. Args: gate_op (QuantumGate): The gate operation to transform. - param_map (dict[str, Union[int, float, bool]]): The parameter map to use + param_map (dict[str, int |float |bool]): The parameter map to use for transformation. Returns: @@ -320,7 +320,7 @@ def get_branch_params( @classmethod def transform_function_qubits( cls, - q_op: Union[QuantumGate, QuantumBarrier, QuantumReset, QuantumPhase], + q_op: QuantumGate | QuantumBarrier | QuantumReset | QuantumPhase, formal_qreg_sizes: dict[str, int], qubit_map: dict[tuple, tuple], ) -> list[IndexedIdentifier]: @@ -356,7 +356,7 @@ def transform_function_qubits( @classmethod def get_target_qubits( cls, - target: Union[Identifier, IndexExpression], + target: Identifier | IndexExpression, qreg_size_map: dict[str, int], target_name: str, ) -> tuple: diff --git a/src/pyqasm/validator.py b/src/pyqasm/validator.py index 524fa75c..048e2753 100644 --- a/src/pyqasm/validator.py +++ b/src/pyqasm/validator.py @@ -16,7 +16,7 @@ Module with utility functions for QASM visitor """ -from typing import Any, Optional, Union +from typing import Any, Optional import numpy as np from openqasm3.ast import ArrayType, ClassicalDeclaration, FloatType @@ -121,8 +121,8 @@ def validate_variable_assignment_value(variable: Variable, value) -> Any: # For each type we will have a "castable" type set and its corresponding cast operation type_casted_value = qasm_variable_type_cast(qasm_type, variable.name, base_size, value) - left: Union[int, float] = 0 - right: Union[int, float] = 0 + left: int | float = 0 + right: int | float = 0 # check 2 - range match , if bits mentioned in base size if type_to_match == int: base_size = variable.base_size diff --git a/src/pyqasm/visitor.py b/src/pyqasm/visitor.py index 47836fa2..1365aa9a 100644 --- a/src/pyqasm/visitor.py +++ b/src/pyqasm/visitor.py @@ -22,7 +22,7 @@ import logging from collections import deque from functools import partial -from typing import Any, Callable, Optional, Union +from typing import Any, Callable, Optional import numpy as np import openqasm3.ast as qasm3_ast @@ -176,7 +176,7 @@ def _check_in_scope(self, var_name: str) -> bool: return True return False - def _get_from_visible_scope(self, var_name: str) -> Union[Variable, None]: + def _get_from_visible_scope(self, var_name: str) -> Variable | None: """ Retrieves a variable from the visible scope. @@ -184,7 +184,7 @@ def _get_from_visible_scope(self, var_name: str) -> Union[Variable, None]: var_name (str): The name of the variable to retrieve. Returns: - Union[Variable, None]: The variable if found, None otherwise. + Variable | None: The variable if found, None otherwise. """ global_scope = self._get_global_scope() curr_scope = self._get_curr_scope() @@ -822,7 +822,7 @@ def _visit_custom_gate_operation( operation: qasm3_ast.QuantumGate, inverse: bool = False, ctrls: Optional[list[qasm3_ast.IndexedIdentifier]] = None, - ) -> list[Union[qasm3_ast.QuantumGate, qasm3_ast.QuantumPhase]]: + ) -> list[qasm3_ast.QuantumGate | qasm3_ast.QuantumPhase]: """Visit a custom gate operation element recursively. Args: @@ -1038,9 +1038,9 @@ def _visit_phase_operation( def _visit_generic_gate_operation( # pylint: disable=too-many-branches self, - operation: Union[qasm3_ast.QuantumGate, qasm3_ast.QuantumPhase], + operation: qasm3_ast.QuantumGate | qasm3_ast.QuantumPhase, ctrls: Optional[list[qasm3_ast.IndexedIdentifier]] = None, - ) -> list[Union[qasm3_ast.QuantumGate, qasm3_ast.QuantumPhase]]: + ) -> list[qasm3_ast.QuantumGate | qasm3_ast.QuantumPhase]: """Visit a gate operation element. Args: @@ -1136,7 +1136,7 @@ def _visit_generic_gate_operation( # pylint: disable=too-many-branches ) # get controlled? inverted? operation x power times - result: list[Union[qasm3_ast.QuantumGate, qasm3_ast.QuantumPhase]] = [] + result: list[qasm3_ast.QuantumGate | qasm3_ast.QuantumPhase] = [] for _ in range(power_value): if isinstance(operation, qasm3_ast.QuantumPhase): result.extend(self._visit_phase_operation(operation, inverse_value, ctrls)) @@ -1373,7 +1373,7 @@ def _visit_classical_assignment( raise_qasm3_error( f"Assignment to constant variable {lvar_name} not allowed", span=statement.span ) - binary_op: Union[str, None, qasm3_ast.BinaryOperator] = None + binary_op: str | None | qasm3_ast.BinaryOperator = None if statement.op != qasm3_ast.AssignmentOperator["="]: # eg. j += 1 -> broken down to j = j + 1 binary_op = statement.op.name.removesuffix("=") From 67e43689fed7f34705cfe8f7077027c3c79f8ae5 Mon Sep 17 00:00:00 2001 From: TheGupta2012 Date: Fri, 11 Apr 2025 14:08:14 +0530 Subject: [PATCH 2/2] add changelog [no ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eda63714..33cc0662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ ValidationError: Expected 1 parameter for gate 'rx', but got 2 ### Deprecated ### Removed +- Removed the dependency on `Union` for typing by replacing it with `|` ([#170](https://github.com/qBraid/pyqasm/pull/170)). ### Fixed - Resolved the inconsistency in `pyqasm.printer.draw` and `pyqasm.printer.mpl_draw` behaviour for multiple function calls. See issue [#165](https://github.com/qBraid/pyqasm/issues/165) for bug details. ([#168](https://github.com/qBraid/pyqasm/pull/168))