From e73e7d10c0bc9a4fc65d3bb9854f2ac82de9bad2 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 03:17:10 +0200 Subject: [PATCH 1/9] feature: support integer division --- src/autoqasm/converters/arithmetic.py | 63 ++++++++++++++++++ src/autoqasm/operators/__init__.py | 1 + src/autoqasm/operators/arithmetic.py | 74 ++++++++++++++++++++++ src/autoqasm/transpiler/transpiler.py | 9 ++- src/autoqasm/types/types.py | 14 ++++ test/unit_tests/autoqasm/test_operators.py | 49 ++++++++++++++ 6 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/autoqasm/converters/arithmetic.py create mode 100644 src/autoqasm/operators/arithmetic.py diff --git a/src/autoqasm/converters/arithmetic.py b/src/autoqasm/converters/arithmetic.py new file mode 100644 index 00000000..9049113d --- /dev/null +++ b/src/autoqasm/converters/arithmetic.py @@ -0,0 +1,63 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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. + +"""Converters for aritmetic operator nodes""" + +import ast + +import gast +from malt.core import ag_ctx, converter +from malt.pyct import templates + +ARITHMETIC_OPERATORS = { + gast.FloorDiv: "ag__.fd_", +} + + +class ArithmeticTransformer(converter.Base): + """Transformer for arithmetic nodes.""" + + def visit_BinOp(self, node: ast.stmt) -> ast.stmt: + """Transforms a BinOp node. + Args : + node(ast.stmt) : AST node to transform + Returns : + ast.stmt : Transformed node + """ + node = self.generic_visit(node) + op_type = type(node.op) + if op_type not in ARITHMETIC_OPERATORS: + return node + + template = f"{ARITHMETIC_OPERATORS[op_type]}(lhs_,rhs_)" + + new_node = templates.replace( + template, + lhs_=node.left, + rhs_=node.right, + original=node, + )[0].value + + return new_node + + +def transform(node: ast.stmt, ctx: ag_ctx.ControlStatusCtx) -> ast.stmt: + """Transform arithmetic nodes. + Args: + node(ast.stmt) : AST node to transform + ctx (ag_ctx.ControlStatusCtx) : Transformer context. + Returns : + ast.stmt : Transformed node. + """ + + return ArithmeticTransformer(ctx).visit(node) diff --git a/src/autoqasm/operators/__init__.py b/src/autoqasm/operators/__init__.py index 04acb310..0e608c55 100644 --- a/src/autoqasm/operators/__init__.py +++ b/src/autoqasm/operators/__init__.py @@ -39,3 +39,4 @@ from .logical import or_ # noqa: F401 from .return_statements import return_output_from_main # noqa: F401 from .slices import GetItemOpts, get_item, set_item # noqa: F401 +from .arithmetic import fd_ # noqa: F401 diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py new file mode 100644 index 00000000..72d8c113 --- /dev/null +++ b/src/autoqasm/operators/arithmetic.py @@ -0,0 +1,74 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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. + +"""Operators for arithmetic operators: // """ + +from __future__ import annotations + +from autoqasm import program +from autoqasm import types as aq_types + +from .utils import _register_and_convert_parameters + + +def fd_( + num_: aq_types.IntVar | aq_types.FloatVar | int | float, + den_: aq_types.IntVar | aq_types.FloatVar | int | float, +) -> int | aq_types.IntVar: + """Functional form of "//". + Args: + num_ (aq_types.IntVar | aq_types.FloatVar | int | float) : + The numerator of the integer division + den_ (aq_types.IntVar | aq_types.FloatVar | int | float) : + The denominator of the integer division + Returns : + int | IntVar : integer division, IntVar if either numerator or denominator + are QASM types, else int + """ + if aq_types.is_qasm_type(num_) or aq_types.is_qasm_type(den_): + return _oqpy_fd(num_, den_) + else: + return _py_fd(num_, den_) + + +def _oqpy_fd( + num_: aq_types.IntVar | aq_types.FloatVar, + den_: aq_types.IntVar | aq_types.FloatVar, +) -> aq_types.IntVar: + num_, den_ = _register_and_convert_parameters(num_, den_) + oqpy_program = program.get_program_conversion_context().get_oqpy_program() + num_is_float = isinstance(num_, aq_types.FloatVar) + den_is_float = isinstance(den_, aq_types.FloatVar) + + # if they are of different types, then one must cast to FloatVar + if num_is_float or den_is_float: + if num_is_float: + float_var = aq_types.FloatVar() + oqpy_program.declare(float_var) + oqpy_program.set(float_var, den_) + if den_is_float: + float_var = aq_types.FloatVar() + oqpy_program.declare(float_var) + oqpy_program.set(float_var, num_) + + result = aq_types.IntVar() + oqpy_program.declare(result) + oqpy_program.set(result, num_ / den_) + return result + + +def _py_fd( + num_: int | float, + den_: int | float, +) -> int: + return num_ // den_ diff --git a/src/autoqasm/transpiler/transpiler.py b/src/autoqasm/transpiler/transpiler.py index 71b455a1..ed1ec175 100644 --- a/src/autoqasm/transpiler/transpiler.py +++ b/src/autoqasm/transpiler/transpiler.py @@ -48,7 +48,13 @@ from malt.utils import ag_logging as logging from autoqasm import operators, program, types -from autoqasm.converters import assignments, break_statements, comparisons, return_statements +from autoqasm.converters import ( + arithmetic, + assignments, + break_statements, + comparisons, + return_statements, +) class PyToOqpy(transpiler.PyToPy): @@ -135,6 +141,7 @@ def transform_ast( node = control_flow.transform(node, ctx) node = conditional_expressions.transform(node, ctx) node = comparisons.transform(node, ctx) + node = arithmetic.transform(node, ctx) node = logical_expressions.transform(node, ctx) node = variables.transform(node, ctx) diff --git a/src/autoqasm/types/types.py b/src/autoqasm/types/types.py index 11bcf2c3..666db86a 100644 --- a/src/autoqasm/types/types.py +++ b/src/autoqasm/types/types.py @@ -15,6 +15,7 @@ from __future__ import annotations +import abc from collections.abc import Iterable from typing import Any, List, Union, get_args @@ -26,6 +27,7 @@ from openpulse import ast from autoqasm import errors, program +from autoqasm.errors import UnsupportedFeatureError def is_qasm_type(val: Any) -> bool: @@ -152,6 +154,12 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar ) self.name = program.get_program_conversion_context().next_var_name(oqpy.FloatVar) + def __floordiv__(self, other): + raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + + def __rfloordiv__(self, other): + raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + class IntVar(oqpy.IntVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): @@ -159,3 +167,9 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar *args, annotations=make_annotations_list(annotations), **kwargs ) self.name = program.get_program_conversion_context().next_var_name(oqpy.IntVar) + + def __floordiv__(self, other): + raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + + def __rfloordiv__(self, other): + raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") diff --git a/test/unit_tests/autoqasm/test_operators.py b/test/unit_tests/autoqasm/test_operators.py index ce3ffd9a..5e3d7d6f 100644 --- a/test/unit_tests/autoqasm/test_operators.py +++ b/test/unit_tests/autoqasm/test_operators.py @@ -930,3 +930,52 @@ def test_list_ops(): assert np.array_equal(c, [[2, 3, 4], [2, 3, 4]]) assert test_list_ops.build().to_ir() + + +class TestFloorDiv: + def test_integer_division_on_intvars(self): + @aq.main(num_qubits=2) + def main(): + a = aq.IntVar(5) + b = aq.IntVar(2) + c = a // b + + expected_ir = """OPENQASM 3.0; +int[32] c; +qubit[2] __qubits__; +int[32] a = 5; +int[32] b = 2; +int[32] __int_2__; +__int_2__ = a / b; +c = __int_2__;""" + assert main.build().to_ir() == expected_ir + + def test_integer_division_on_mixed_vars(self): + @aq.main(num_qubits=2) + def main(): + a = aq.IntVar(5) + b = aq.FloatVar(2.3) + c = a // b + + expected_ir = """OPENQASM 3.0; +int[32] c; +qubit[2] __qubits__; +int[32] a = 5; +float[64] b = 2.3; +float[64] __float_2__; +__float_2__ = a; +int[32] __int_3__; +__int_3__ = a / b; +c = __int_3__;""" + assert main.build().to_ir() == expected_ir + + def test_integer_division_on_python_types(self): + @aq.main(num_qubits=2) + def main(): + a = 5 + b = 2.3 + c = a // b + + expected_ir = """OPENQASM 3.0; +qubit[2] __qubits__;""" + assert main.build().to_ir() == expected_ir From b7a4996f9a82f96736e1adb8fea410e980b3624f Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 03:21:34 +0200 Subject: [PATCH 2/9] fix: fix typos --- src/autoqasm/types/types.py | 1 - test/unit_tests/autoqasm/test_operators.py | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/autoqasm/types/types.py b/src/autoqasm/types/types.py index 666db86a..ea49ec15 100644 --- a/src/autoqasm/types/types.py +++ b/src/autoqasm/types/types.py @@ -15,7 +15,6 @@ from __future__ import annotations -import abc from collections.abc import Iterable from typing import Any, List, Union, get_args diff --git a/test/unit_tests/autoqasm/test_operators.py b/test/unit_tests/autoqasm/test_operators.py index 5e3d7d6f..a9e770a8 100644 --- a/test/unit_tests/autoqasm/test_operators.py +++ b/test/unit_tests/autoqasm/test_operators.py @@ -938,7 +938,7 @@ def test_integer_division_on_intvars(self): def main(): a = aq.IntVar(5) b = aq.IntVar(2) - c = a // b + c = a // b # noqa: F841 expected_ir = """OPENQASM 3.0; int[32] c; @@ -955,7 +955,7 @@ def test_integer_division_on_mixed_vars(self): def main(): a = aq.IntVar(5) b = aq.FloatVar(2.3) - c = a // b + c = a // b # noqa: F841 expected_ir = """OPENQASM 3.0; int[32] c; @@ -974,7 +974,7 @@ def test_integer_division_on_python_types(self): def main(): a = 5 b = 2.3 - c = a // b + c = a // b # noqa: F841 expected_ir = """OPENQASM 3.0; qubit[2] __qubits__;""" From be876b19a89f54d71a1eea05603757e3259ecb53 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 16:10:50 +0200 Subject: [PATCH 3/9] fix: fix imports --- src/autoqasm/operators/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoqasm/operators/__init__.py b/src/autoqasm/operators/__init__.py index 0e608c55..85738251 100644 --- a/src/autoqasm/operators/__init__.py +++ b/src/autoqasm/operators/__init__.py @@ -21,6 +21,7 @@ from malt.impl.api import autograph_artifact # noqa: F401 from malt.operators.variables import Undefined, UndefinedReturnValue, ld, ldu # noqa: F401 +from .arithmetic import fd_ # noqa: F401 from .assignments import assign_for_output, assign_stmt # noqa: F401 from .comparisons import gt_, gteq_, lt_, lteq_ # noqa: F401 from .conditional_expressions import if_exp # noqa: F401 @@ -39,4 +40,3 @@ from .logical import or_ # noqa: F401 from .return_statements import return_output_from_main # noqa: F401 from .slices import GetItemOpts, get_item, set_item # noqa: F401 -from .arithmetic import fd_ # noqa: F401 From 6a29f1841683f4f8f2211acccdcb5bd1b0ccfc1e Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 16:42:39 +0200 Subject: [PATCH 4/9] fix: apply suggestions from code review Co-authored-by: Ryan Shaffer <3620100+rmshaffer@users.noreply.github.com> --- src/autoqasm/operators/arithmetic.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index 72d8c113..4b5d8220 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -42,24 +42,25 @@ def fd_( def _oqpy_fd( - num_: aq_types.IntVar | aq_types.FloatVar, - den_: aq_types.IntVar | aq_types.FloatVar, + num_: aq_types.IntVar | aq_types.FloatVar | int | float, + den_: aq_types.IntVar | aq_types.FloatVar | int | float, ) -> aq_types.IntVar: num_, den_ = _register_and_convert_parameters(num_, den_) oqpy_program = program.get_program_conversion_context().get_oqpy_program() - num_is_float = isinstance(num_, aq_types.FloatVar) - den_is_float = isinstance(den_, aq_types.FloatVar) + num_is_float = isinstance(num_, (aq_types.FloatVar, float)) + den_is_float = isinstance(den_, (aq_types.FloatVar, float)) # if they are of different types, then one must cast to FloatVar - if num_is_float or den_is_float: - if num_is_float: - float_var = aq_types.FloatVar() - oqpy_program.declare(float_var) - oqpy_program.set(float_var, den_) - if den_is_float: - float_var = aq_types.FloatVar() - oqpy_program.declare(float_var) - oqpy_program.set(float_var, num_) + if num_is_float and not den_is_float: + den_float_var = aq_types.FloatVar() + oqpy_program.declare(den_float_var) + oqpy_program.set(den_float_var, den_) + den_ = den_float_var + if den_is_float and not num_is_float: + num_float_var = aq_types.FloatVar() + oqpy_program.declare(num_float_var) + oqpy_program.set(num_float_var, num_ ) + num_ = num_float_var result = aq_types.IntVar() oqpy_program.declare(result) From e7a50b084513d81c3dcefcfcd9353aba70cb0893 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 16:48:12 +0200 Subject: [PATCH 5/9] fix: add linting and coverage fixes --- src/autoqasm/operators/arithmetic.py | 8 +++----- src/autoqasm/types/types.py | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index 4b5d8220..cef5d2d7 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -27,10 +27,8 @@ def fd_( ) -> int | aq_types.IntVar: """Functional form of "//". Args: - num_ (aq_types.IntVar | aq_types.FloatVar | int | float) : - The numerator of the integer division - den_ (aq_types.IntVar | aq_types.FloatVar | int | float) : - The denominator of the integer division + num_ (IntVar | FloatVar | int | float) : The numerator of the integer division + den_ (IntVar | FloatVar | int | float) : The denominator of the integer division Returns : int | IntVar : integer division, IntVar if either numerator or denominator are QASM types, else int @@ -59,7 +57,7 @@ def _oqpy_fd( if den_is_float and not num_is_float: num_float_var = aq_types.FloatVar() oqpy_program.declare(num_float_var) - oqpy_program.set(num_float_var, num_ ) + oqpy_program.set(num_float_var, num_) num_ = num_float_var result = aq_types.IntVar() diff --git a/src/autoqasm/types/types.py b/src/autoqasm/types/types.py index ea49ec15..b630025d 100644 --- a/src/autoqasm/types/types.py +++ b/src/autoqasm/types/types.py @@ -26,7 +26,6 @@ from openpulse import ast from autoqasm import errors, program -from autoqasm.errors import UnsupportedFeatureError def is_qasm_type(val: Any) -> bool: @@ -154,10 +153,10 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar self.name = program.get_program_conversion_context().next_var_name(oqpy.FloatVar) def __floordiv__(self, other): - raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + raise NotImplementedError("Integer division is supported by OpenQASM.") def __rfloordiv__(self, other): - raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + raise NotImplementedError("Integer division is supported by OpenQASM.") class IntVar(oqpy.IntVar): @@ -168,7 +167,7 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar self.name = program.get_program_conversion_context().next_var_name(oqpy.IntVar) def __floordiv__(self, other): - raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + raise NotImplementedError("Integer division is supported by OpenQASM.") def __rfloordiv__(self, other): - raise UnsupportedFeatureError("Integer division is supported by OpenQASM.") + raise NotImplementedError("Integer division is supported by OpenQASM.") From 602b6601ff25e3da01e6c839c2d9f281e2466738 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 17:22:30 +0200 Subject: [PATCH 6/9] fix: return float in integer division --- src/autoqasm/operators/arithmetic.py | 11 ++++++++--- test/unit_tests/autoqasm/test_operators.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index cef5d2d7..13609789 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -48,7 +48,7 @@ def _oqpy_fd( num_is_float = isinstance(num_, (aq_types.FloatVar, float)) den_is_float = isinstance(den_, (aq_types.FloatVar, float)) - # if they are of different types, then one must cast to FloatVar + # if either is a FloatVar, then both must be FloatVar if num_is_float and not den_is_float: den_float_var = aq_types.FloatVar() oqpy_program.declare(den_float_var) @@ -60,7 +60,12 @@ def _oqpy_fd( oqpy_program.set(num_float_var, num_) num_ = num_float_var - result = aq_types.IntVar() + # if either is a FloatVar, then the result will be a FloatVar + if num_is_float or den_is_float: + result = aq_types.FloatVar() + else: + result = aq_types.IntVar() + oqpy_program.declare(result) oqpy_program.set(result, num_ / den_) return result @@ -69,5 +74,5 @@ def _oqpy_fd( def _py_fd( num_: int | float, den_: int | float, -) -> int: +) -> int | float: return num_ // den_ diff --git a/test/unit_tests/autoqasm/test_operators.py b/test/unit_tests/autoqasm/test_operators.py index a9e770a8..e07ec0ca 100644 --- a/test/unit_tests/autoqasm/test_operators.py +++ b/test/unit_tests/autoqasm/test_operators.py @@ -958,15 +958,15 @@ def main(): c = a // b # noqa: F841 expected_ir = """OPENQASM 3.0; -int[32] c; +float[64] c; qubit[2] __qubits__; int[32] a = 5; float[64] b = 2.3; float[64] __float_2__; __float_2__ = a; -int[32] __int_3__; -__int_3__ = a / b; -c = __int_3__;""" +float[64] __float_3__; +__float_3__ = __float_2__ / b; +c = __float_3__;""" assert main.build().to_ir() == expected_ir def test_integer_division_on_python_types(self): From f7ae401c063fd3c79e5a4477e3efc0b09eb046f0 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Tue, 11 Jun 2024 20:04:16 +0200 Subject: [PATCH 7/9] fix: return float in integer division when appropriate --- src/autoqasm/operators/arithmetic.py | 15 +++++++++------ test/unit_tests/autoqasm/test_operators.py | 17 ++++++++++++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index 13609789..1078a098 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -42,7 +42,7 @@ def fd_( def _oqpy_fd( num_: aq_types.IntVar | aq_types.FloatVar | int | float, den_: aq_types.IntVar | aq_types.FloatVar | int | float, -) -> aq_types.IntVar: +) -> aq_types.IntVar | aq_types.FloatVar: num_, den_ = _register_and_convert_parameters(num_, den_) oqpy_program = program.get_program_conversion_context().get_oqpy_program() num_is_float = isinstance(num_, (aq_types.FloatVar, float)) @@ -61,13 +61,16 @@ def _oqpy_fd( num_ = num_float_var # if either is a FloatVar, then the result will be a FloatVar - if num_is_float or den_is_float: - result = aq_types.FloatVar() - else: - result = aq_types.IntVar() - + result = aq_types.IntVar() oqpy_program.declare(result) oqpy_program.set(result, num_ / den_) + + if num_is_float or den_is_float: + float_result = aq_types.FloatVar() + oqpy_program.declare(float_result) + oqpy_program.set(float_result, result) + return float_result + return result diff --git a/test/unit_tests/autoqasm/test_operators.py b/test/unit_tests/autoqasm/test_operators.py index e07ec0ca..4ad5399f 100644 --- a/test/unit_tests/autoqasm/test_operators.py +++ b/test/unit_tests/autoqasm/test_operators.py @@ -956,17 +956,28 @@ def main(): a = aq.IntVar(5) b = aq.FloatVar(2.3) c = a // b # noqa: F841 + d = b // a # noqa: F841 expected_ir = """OPENQASM 3.0; float[64] c; +float[64] d; qubit[2] __qubits__; int[32] a = 5; float[64] b = 2.3; float[64] __float_2__; __float_2__ = a; -float[64] __float_3__; -__float_3__ = __float_2__ / b; -c = __float_3__;""" +int[32] __int_3__; +__int_3__ = __float_2__ / b; +float[64] __float_4__; +__float_4__ = __int_3__; +c = __float_4__; +float[64] __float_5__; +__float_5__ = a; +int[32] __int_6__; +__int_6__ = b / __float_5__; +float[64] __float_7__; +__float_7__ = __int_6__; +d = __float_7__;""" assert main.build().to_ir() == expected_ir def test_integer_division_on_python_types(self): From 0cea7ec40741e7b13e34ef9a7bba2afadfecd3c2 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Wed, 12 Jun 2024 18:54:04 +0200 Subject: [PATCH 8/9] fix: add cosmetic changes --- src/autoqasm/converters/arithmetic.py | 2 +- src/autoqasm/operators/__init__.py | 2 +- src/autoqasm/operators/arithmetic.py | 46 +++++++++--------- test/unit_tests/autoqasm/test_operators.py | 55 +++++++++++----------- 4 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/autoqasm/converters/arithmetic.py b/src/autoqasm/converters/arithmetic.py index 9049113d..edc6a360 100644 --- a/src/autoqasm/converters/arithmetic.py +++ b/src/autoqasm/converters/arithmetic.py @@ -20,7 +20,7 @@ from malt.pyct import templates ARITHMETIC_OPERATORS = { - gast.FloorDiv: "ag__.fd_", + gast.FloorDiv: "ag__.floor_div", } diff --git a/src/autoqasm/operators/__init__.py b/src/autoqasm/operators/__init__.py index 85738251..7b8b28ab 100644 --- a/src/autoqasm/operators/__init__.py +++ b/src/autoqasm/operators/__init__.py @@ -21,7 +21,7 @@ from malt.impl.api import autograph_artifact # noqa: F401 from malt.operators.variables import Undefined, UndefinedReturnValue, ld, ldu # noqa: F401 -from .arithmetic import fd_ # noqa: F401 +from .arithmetic import floor_div # noqa: F401 from .assignments import assign_for_output, assign_stmt # noqa: F401 from .comparisons import gt_, gteq_, lt_, lteq_ # noqa: F401 from .conditional_expressions import if_exp # noqa: F401 diff --git a/src/autoqasm/operators/arithmetic.py b/src/autoqasm/operators/arithmetic.py index 1078a098..1decb7d2 100644 --- a/src/autoqasm/operators/arithmetic.py +++ b/src/autoqasm/operators/arithmetic.py @@ -21,49 +21,49 @@ from .utils import _register_and_convert_parameters -def fd_( - num_: aq_types.IntVar | aq_types.FloatVar | int | float, - den_: aq_types.IntVar | aq_types.FloatVar | int | float, +def floor_div( + num: aq_types.IntVar | aq_types.FloatVar | int | float, + den: aq_types.IntVar | aq_types.FloatVar | int | float, ) -> int | aq_types.IntVar: """Functional form of "//". Args: - num_ (IntVar | FloatVar | int | float) : The numerator of the integer division - den_ (IntVar | FloatVar | int | float) : The denominator of the integer division + num (IntVar | FloatVar | int | float) : The numerator of the integer division + den (IntVar | FloatVar | int | float) : The denominator of the integer division Returns : int | IntVar : integer division, IntVar if either numerator or denominator are QASM types, else int """ - if aq_types.is_qasm_type(num_) or aq_types.is_qasm_type(den_): - return _oqpy_fd(num_, den_) + if aq_types.is_qasm_type(num) or aq_types.is_qasm_type(den): + return _oqpy_floor_div(num, den) else: - return _py_fd(num_, den_) + return _py_floor_div(num, den) -def _oqpy_fd( - num_: aq_types.IntVar | aq_types.FloatVar | int | float, - den_: aq_types.IntVar | aq_types.FloatVar | int | float, +def _oqpy_floor_div( + num: aq_types.IntVar | aq_types.FloatVar | int | float, + den: aq_types.IntVar | aq_types.FloatVar | int | float, ) -> aq_types.IntVar | aq_types.FloatVar: - num_, den_ = _register_and_convert_parameters(num_, den_) + num, den = _register_and_convert_parameters(num, den) oqpy_program = program.get_program_conversion_context().get_oqpy_program() - num_is_float = isinstance(num_, (aq_types.FloatVar, float)) - den_is_float = isinstance(den_, (aq_types.FloatVar, float)) + num_is_float = isinstance(num, (aq_types.FloatVar, float)) + den_is_float = isinstance(den, (aq_types.FloatVar, float)) # if either is a FloatVar, then both must be FloatVar if num_is_float and not den_is_float: den_float_var = aq_types.FloatVar() oqpy_program.declare(den_float_var) - oqpy_program.set(den_float_var, den_) - den_ = den_float_var + oqpy_program.set(den_float_var, den) + den = den_float_var if den_is_float and not num_is_float: num_float_var = aq_types.FloatVar() oqpy_program.declare(num_float_var) - oqpy_program.set(num_float_var, num_) - num_ = num_float_var + oqpy_program.set(num_float_var, num) + num = num_float_var # if either is a FloatVar, then the result will be a FloatVar result = aq_types.IntVar() oqpy_program.declare(result) - oqpy_program.set(result, num_ / den_) + oqpy_program.set(result, num / den) if num_is_float or den_is_float: float_result = aq_types.FloatVar() @@ -74,8 +74,8 @@ def _oqpy_fd( return result -def _py_fd( - num_: int | float, - den_: int | float, +def _py_floor_div( + num: int | float, + den: int | float, ) -> int | float: - return num_ // den_ + return num // den diff --git a/test/unit_tests/autoqasm/test_operators.py b/test/unit_tests/autoqasm/test_operators.py index 4ad5399f..436da5cc 100644 --- a/test/unit_tests/autoqasm/test_operators.py +++ b/test/unit_tests/autoqasm/test_operators.py @@ -932,15 +932,14 @@ def test_list_ops(): assert test_list_ops.build().to_ir() -class TestFloorDiv: - def test_integer_division_on_intvars(self): - @aq.main(num_qubits=2) - def main(): - a = aq.IntVar(5) - b = aq.IntVar(2) - c = a // b # noqa: F841 - - expected_ir = """OPENQASM 3.0; +def test_integer_division_on_intvars(): + @aq.main(num_qubits=2) + def main(): + a = aq.IntVar(5) + b = aq.IntVar(2) + c = a // b # noqa: F841 + + expected_ir = """OPENQASM 3.0; int[32] c; qubit[2] __qubits__; int[32] a = 5; @@ -948,17 +947,18 @@ def main(): int[32] __int_2__; __int_2__ = a / b; c = __int_2__;""" - assert main.build().to_ir() == expected_ir + assert main.build().to_ir() == expected_ir - def test_integer_division_on_mixed_vars(self): - @aq.main(num_qubits=2) - def main(): - a = aq.IntVar(5) - b = aq.FloatVar(2.3) - c = a // b # noqa: F841 - d = b // a # noqa: F841 - expected_ir = """OPENQASM 3.0; +def test_integer_division_on_mixed_vars(): + @aq.main(num_qubits=2) + def main(): + a = aq.IntVar(5) + b = aq.FloatVar(2.3) + c = a // b # noqa: F841 + d = b // a # noqa: F841 + + expected_ir = """OPENQASM 3.0; float[64] c; float[64] d; qubit[2] __qubits__; @@ -978,15 +978,16 @@ def main(): float[64] __float_7__; __float_7__ = __int_6__; d = __float_7__;""" - assert main.build().to_ir() == expected_ir + assert main.build().to_ir() == expected_ir + - def test_integer_division_on_python_types(self): - @aq.main(num_qubits=2) - def main(): - a = 5 - b = 2.3 - c = a // b # noqa: F841 +def test_integer_division_on_python_types(): + @aq.main(num_qubits=2) + def main(): + a = 5 + b = 2.3 + c = a // b # noqa: F841 - expected_ir = """OPENQASM 3.0; + expected_ir = """OPENQASM 3.0; qubit[2] __qubits__;""" - assert main.build().to_ir() == expected_ir + assert main.build().to_ir() == expected_ir From f44b48edb50907706132092d148b0433ed110741 Mon Sep 17 00:00:00 2001 From: Alan Bidart Date: Wed, 12 Jun 2024 21:41:25 +0200 Subject: [PATCH 9/9] fix: remove methods added for linting --- src/autoqasm/types/types.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/autoqasm/types/types.py b/src/autoqasm/types/types.py index b630025d..11bcf2c3 100644 --- a/src/autoqasm/types/types.py +++ b/src/autoqasm/types/types.py @@ -152,12 +152,6 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar ) self.name = program.get_program_conversion_context().next_var_name(oqpy.FloatVar) - def __floordiv__(self, other): - raise NotImplementedError("Integer division is supported by OpenQASM.") - - def __rfloordiv__(self, other): - raise NotImplementedError("Integer division is supported by OpenQASM.") - class IntVar(oqpy.IntVar): def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwargs): @@ -165,9 +159,3 @@ def __init__(self, *args, annotations: str | Iterable[str] | None = None, **kwar *args, annotations=make_annotations_list(annotations), **kwargs ) self.name = program.get_program_conversion_context().next_var_name(oqpy.IntVar) - - def __floordiv__(self, other): - raise NotImplementedError("Integer division is supported by OpenQASM.") - - def __rfloordiv__(self, other): - raise NotImplementedError("Integer division is supported by OpenQASM.")