From d449170f6c1f1425820c6b05087c8d60435397c8 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Sat, 25 Nov 2023 15:08:16 +0100 Subject: [PATCH 1/6] ignore vscode settings --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c0fbca27..9f6e407f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ test/unit_tests/.DS_Store test/unit_tests/braket/.DS_Store test/.benchmarks .DS_Store +.vscode/* From 6dbe0a4cdba2d8643a7f5aad0f81175096227ec9 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Sun, 26 Nov 2023 12:00:11 +0100 Subject: [PATCH 2/6] allow negctrl gphase --- .../openqasm/_helpers/quantum.py | 18 +++++++++++---- .../openqasm/program_context.py | 23 +++++++++++++++---- .../openqasm/test_interpreter.py | 14 ++++++----- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/braket/default_simulator/openqasm/_helpers/quantum.py b/src/braket/default_simulator/openqasm/_helpers/quantum.py index 7d890353..b007fcf8 100644 --- a/src/braket/default_simulator/openqasm/_helpers/quantum.py +++ b/src/braket/default_simulator/openqasm/_helpers/quantum.py @@ -54,17 +54,16 @@ def is_controlled(phase: QuantumPhase) -> bool: return False -def convert_phase_to_gate(controlled_phase: QuantumPhase) -> QuantumGate: +def convert_phase_to_gate(controlled_phase: QuantumPhase) -> QuantumGate | list[QuantumGate]: """Convert a controlled quantum phase into a quantum gate""" ctrl_modifiers = get_ctrl_modifiers(controlled_phase.modifiers) first_ctrl_modifier = ctrl_modifiers[-1] - if first_ctrl_modifier.modifier == GateModifierName.negctrl: - raise ValueError("negctrl modifier undefined for gphase operation") if first_ctrl_modifier.argument.value == 1: ctrl_modifiers.pop() else: ctrl_modifiers[-1].argument.value -= 1 - return QuantumGate( + + ctrl_phaseshift = QuantumGate( ctrl_modifiers, Identifier("U"), [ @@ -75,6 +74,17 @@ def convert_phase_to_gate(controlled_phase: QuantumPhase) -> QuantumGate: controlled_phase.qubits, ) + if first_ctrl_modifier.modifier == GateModifierName.negctrl: + X = QuantumGate( + [], + Identifier("U"), + [Identifier("π"), IntegerLiteral(0), Identifier("π")], + controlled_phase.qubits, + ) + return [X, ctrl_phaseshift, X] + else: + return ctrl_phaseshift + def get_ctrl_modifiers(modifiers: list[QuantumGateModifier]) -> list[QuantumGateModifier]: """Get the control modifiers from a list of quantum gate modifiers""" diff --git a/src/braket/default_simulator/openqasm/program_context.py b/src/braket/default_simulator/openqasm/program_context.py index c845d894..a2f24b94 100644 --- a/src/braket/default_simulator/openqasm/program_context.py +++ b/src/braket/default_simulator/openqasm/program_context.py @@ -421,7 +421,12 @@ def circuit(self): def __repr__(self): return "\n\n".join( repr(x) - for x in (self.symbol_table, self.variable_table, self.gate_table, self.qubit_mapping) + for x in ( + self.symbol_table, + self.variable_table, + self.gate_table, + self.qubit_mapping, + ) ) def load_inputs(self, inputs: dict[str, Any]) -> None: @@ -782,7 +787,12 @@ def handle_parameter_value(self, value: Union[float, Expr]) -> Any: @abstractmethod def add_gate_instruction( - self, gate_name: str, target: tuple[int, ...], params, ctrl_modifiers: list[int], power: int + self, + gate_name: str, + target: tuple[int, ...], + params, + ctrl_modifiers: list[int], + power: int, ): """Abstract method to add Braket gate to the circuit. Args: @@ -849,12 +859,17 @@ def is_builtin_gate(self, name: str) -> bool: user_defined_gate = self.is_user_defined_gate(name) return name in BRAKET_GATES and not user_defined_gate - def add_phase_instruction(self, target: tuple[int], phase_value: int): + def add_phase_instruction(self, target: tuple[int], phase_value: float): phase_instruction = GPhase(target, phase_value) self._circuit.add_instruction(phase_instruction) def add_gate_instruction( - self, gate_name: str, target: tuple[int, ...], params, ctrl_modifiers: list[int], power: int + self, + gate_name: str, + target: tuple[int, ...], + params, + ctrl_modifiers: list[int], + power: int, ): instruction = BRAKET_GATES[gate_name]( target, *params, ctrl_modifiers=ctrl_modifiers, power=power diff --git a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py index eb976444..ce99e3c4 100644 --- a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py +++ b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py @@ -1075,13 +1075,15 @@ def test_gphase(): def test_no_neg_ctrl_phase(): qasm = """ - gate bad_phase a { - negctrl @ gphase(π/2); - } + qubit q; + h q; + negctrl @ gphase(π) q; + h q; """ - no_negctrl = "negctrl modifier undefined for gphase operation" - with pytest.raises(ValueError, match=no_negctrl): - Interpreter().run(qasm) + circuit = Interpreter().build_circuit(qasm) + simulation = StateVectorSimulation(1, 1, 1) + simulation.evolve(circuit.instructions) + assert np.allclose(simulation.state_vector, [0, -1]) def test_if(): From c4f2cdadff0d676455d3838442ba0376c9428c89 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Thu, 30 Nov 2023 11:52:56 +0100 Subject: [PATCH 3/6] warn gphase is not supported by the service --- src/braket/default_simulator/openqasm/interpreter.py | 1 + .../braket/default_simulator/openqasm/test_interpreter.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/braket/default_simulator/openqasm/interpreter.py b/src/braket/default_simulator/openqasm/interpreter.py index d2c2d795..f1bdbfd4 100644 --- a/src/braket/default_simulator/openqasm/interpreter.py +++ b/src/braket/default_simulator/openqasm/interpreter.py @@ -447,6 +447,7 @@ def _(self, node: QuantumGate) -> None: @visit.register def _(self, node: QuantumPhase) -> None: + self._uses_advanced_language_features = True node.argument = self.visit(node.argument) node.modifiers = self.visit(node.modifiers) if is_inverted(node): diff --git a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py index ce99e3c4..9efc05ef 100644 --- a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py +++ b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py @@ -1922,6 +1922,7 @@ def test_noise(): ( "const int x = 4;", "qubit[2] q; h q[0:1];", + "gphase(0.15);", "gate my_x q { x q; }", "qubit[2] q; ctrl @ x q[0], q[1];", "qubit q; if (1) { x q; }", From 6f18a9af40dfb273af10204914254e70be2f44b7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Thu, 30 Nov 2023 13:15:34 +0100 Subject: [PATCH 4/6] update test name --- .../openqasm/_helpers/quantum.py | 2 +- .../openqasm/test_interpreter.py | 35 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/braket/default_simulator/openqasm/_helpers/quantum.py b/src/braket/default_simulator/openqasm/_helpers/quantum.py index b007fcf8..3e43ace0 100644 --- a/src/braket/default_simulator/openqasm/_helpers/quantum.py +++ b/src/braket/default_simulator/openqasm/_helpers/quantum.py @@ -54,7 +54,7 @@ def is_controlled(phase: QuantumPhase) -> bool: return False -def convert_phase_to_gate(controlled_phase: QuantumPhase) -> QuantumGate | list[QuantumGate]: +def convert_phase_to_gate(controlled_phase: QuantumPhase) -> Union[QuantumGate, list[QuantumGate]]: """Convert a controlled quantum phase into a quantum gate""" ctrl_modifiers = get_ctrl_modifiers(controlled_phase.modifiers) first_ctrl_modifier = ctrl_modifiers[-1] diff --git a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py index 9efc05ef..1098b342 100644 --- a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py +++ b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py @@ -306,10 +306,12 @@ def test_array_declaration(): base_type=IntType(), dimensions=[IntegerLiteral(2)] ) assert context.get_type("multi_dim") == ArrayType( - base_type=UintType(IntegerLiteral(8)), dimensions=[IntegerLiteral(2), IntegerLiteral(2)] + base_type=UintType(IntegerLiteral(8)), + dimensions=[IntegerLiteral(2), IntegerLiteral(2)], ) assert context.get_type("by_ref") == ArrayType( - base_type=UintType(IntegerLiteral(8)), dimensions=[IntegerLiteral(2), IntegerLiteral(2)] + base_type=UintType(IntegerLiteral(8)), + dimensions=[IntegerLiteral(2), IntegerLiteral(2)], ) assert context.get_type("with_expressions") == ArrayType( base_type=UintType(IntegerLiteral(8)), @@ -402,7 +404,8 @@ def test_indexed_expression(): context = Interpreter().run(qasm) assert context.get_type("multi_dim") == ArrayType( - base_type=UintType(IntegerLiteral(8)), dimensions=[IntegerLiteral(2), IntegerLiteral(2)] + base_type=UintType(IntegerLiteral(8)), + dimensions=[IntegerLiteral(2), IntegerLiteral(2)], ) assert context.get_type("int_from_array") == IntType(IntegerLiteral(8)) assert context.get_type("array_from_array") == ArrayType( @@ -412,7 +415,8 @@ def test_indexed_expression(): base_type=UintType(IntegerLiteral(8)), dimensions=[IntegerLiteral(3)] ) assert context.get_type("using_set_multi_dim") == ArrayType( - base_type=UintType(IntegerLiteral(8)), dimensions=[IntegerLiteral(3), IntegerLiteral(2)] + base_type=UintType(IntegerLiteral(8)), + dimensions=[IntegerLiteral(3), IntegerLiteral(2)], ) assert context.get_value("multi_dim") == ArrayLiteral( @@ -649,7 +653,12 @@ def test_indexed_identifier(): ] ) assert context.get_value("two") == ArrayLiteral( - [BooleanLiteral(False), BooleanLiteral(False), BooleanLiteral(True), BooleanLiteral(False)] + [ + BooleanLiteral(False), + BooleanLiteral(False), + BooleanLiteral(True), + BooleanLiteral(False), + ] ) @@ -1073,7 +1082,7 @@ def test_gphase(): assert np.allclose(simulation.state_vector, [-1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)]) -def test_no_neg_ctrl_phase(): +def test_neg_ctrl_phase(): qasm = """ qubit q; h q; @@ -1781,10 +1790,20 @@ def classical(bit[4] bits) { """ context = Interpreter().run(qasm) assert context.get_value("before") == ArrayLiteral( - [BooleanLiteral(False), BooleanLiteral(False), BooleanLiteral(False), BooleanLiteral(False)] + [ + BooleanLiteral(False), + BooleanLiteral(False), + BooleanLiteral(False), + BooleanLiteral(False), + ] ) assert context.get_value("after") == ArrayLiteral( - [BooleanLiteral(True), BooleanLiteral(False), BooleanLiteral(False), BooleanLiteral(False)] + [ + BooleanLiteral(True), + BooleanLiteral(False), + BooleanLiteral(False), + BooleanLiteral(False), + ] ) From 6648e2726dccc1eb33a51905f08a7eda31234f79 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Mon, 4 Dec 2023 17:32:08 +0100 Subject: [PATCH 5/6] fixes according to feedbacl --- .../openqasm/_helpers/quantum.py | 6 +-- .../default_simulator/openqasm/interpreter.py | 8 ++- .../openqasm/test_interpreter.py | 51 ++++++++++++++++--- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/braket/default_simulator/openqasm/_helpers/quantum.py b/src/braket/default_simulator/openqasm/_helpers/quantum.py index 3e43ace0..ab52f179 100644 --- a/src/braket/default_simulator/openqasm/_helpers/quantum.py +++ b/src/braket/default_simulator/openqasm/_helpers/quantum.py @@ -77,9 +77,9 @@ def convert_phase_to_gate(controlled_phase: QuantumPhase) -> Union[QuantumGate, if first_ctrl_modifier.modifier == GateModifierName.negctrl: X = QuantumGate( [], - Identifier("U"), - [Identifier("π"), IntegerLiteral(0), Identifier("π")], - controlled_phase.qubits, + Identifier("x"), + [], + [controlled_phase.qubits[-1]], ) return [X, ctrl_phaseshift, X] else: diff --git a/src/braket/default_simulator/openqasm/interpreter.py b/src/braket/default_simulator/openqasm/interpreter.py index f1bdbfd4..a7222559 100644 --- a/src/braket/default_simulator/openqasm/interpreter.py +++ b/src/braket/default_simulator/openqasm/interpreter.py @@ -311,7 +311,8 @@ def _(self, node: QuantumGateDefinition) -> None: def inline_gate_def_body(self, body: list[QuantumStatement]) -> list[QuantumStatement]: inlined_body = [] - for statement in body: + statement = body.pop(0) if body else None + while statement is not None: if isinstance(statement, QuantumPhase): statement.argument = self.visit(statement.argument) statement.modifiers = self.visit(statement.modifiers) @@ -319,6 +320,10 @@ def inline_gate_def_body(self, body: list[QuantumStatement]) -> list[QuantumStat statement = invert_phase(statement) if is_controlled(statement): statement = convert_phase_to_gate(statement) + if isinstance(statement, list): + for gate in reversed(statement): + body.insert(0, gate) + continue # statement is a quantum phase instruction else: inlined_body.append(statement) @@ -358,6 +363,7 @@ def inline_gate_def_body(self, body: list[QuantumStatement]) -> list[QuantumStat ctrl_qubits, pow_modifiers, ) + statement = body.pop(0) if body else None return inlined_body @visit.register diff --git a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py index 1098b342..4a52cbf9 100644 --- a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py +++ b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py @@ -54,12 +54,14 @@ BoolType, FloatLiteral, FloatType, + GateModifierName, Identifier, IndexedIdentifier, IntegerLiteral, IntType, QuantumGate, QuantumGateDefinition, + QuantumGateModifier, SymbolLiteral, UintType, ) @@ -1084,15 +1086,50 @@ def test_gphase(): def test_neg_ctrl_phase(): qasm = """ - qubit q; - h q; - negctrl @ gphase(π) q; - h q; + gate some_ctrl_gphase(λ) a, b { ctrl @ negctrl @ gphase(λ) a, b; } + qubit[2] q; + x q[0]; + h q[1]; + some_ctrl_gphase(π) q[0], q[1]; + h q[1]; """ - circuit = Interpreter().build_circuit(qasm) - simulation = StateVectorSimulation(1, 1, 1) + context = Interpreter().run(qasm) + circuit = context.circuit + simulation = StateVectorSimulation(2, 1, 1) simulation.evolve(circuit.instructions) - assert np.allclose(simulation.state_vector, [0, -1]) + assert np.allclose(simulation.state_vector, [0, 0, 0, -1]) + + assert context.get_gate_definition("some_ctrl_gphase") == QuantumGateDefinition( + name=Identifier("some_ctrl_gphase"), + arguments=[Identifier("λ")], + qubits=[Identifier("a"), Identifier("b")], + body=[ + QuantumGate( + modifiers=[], + name=Identifier("x"), + arguments=[], + qubits=[Identifier("b")], + ), + QuantumGate( + modifiers=[ + QuantumGateModifier(modifier=GateModifierName.ctrl, argument=IntegerLiteral(1)) + ], + name=Identifier("U"), + arguments=[ + IntegerLiteral(0), + IntegerLiteral(0), + Identifier("λ"), + ], + qubits=[Identifier("a"), Identifier("b")], + ), + QuantumGate( + modifiers=[], + name=Identifier("x"), + arguments=[], + qubits=[Identifier("b")], + ), + ], + ) def test_if(): From e34143d65d717f46562e7e7ce03c1d6e60b5b0fb Mon Sep 17 00:00:00 2001 From: Jean-Christophe Jaskula Date: Mon, 4 Dec 2023 17:35:56 +0100 Subject: [PATCH 6/6] remove warning --- src/braket/default_simulator/openqasm/interpreter.py | 1 - .../braket/default_simulator/openqasm/test_interpreter.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/braket/default_simulator/openqasm/interpreter.py b/src/braket/default_simulator/openqasm/interpreter.py index a7222559..5bec7415 100644 --- a/src/braket/default_simulator/openqasm/interpreter.py +++ b/src/braket/default_simulator/openqasm/interpreter.py @@ -453,7 +453,6 @@ def _(self, node: QuantumGate) -> None: @visit.register def _(self, node: QuantumPhase) -> None: - self._uses_advanced_language_features = True node.argument = self.visit(node.argument) node.modifiers = self.visit(node.modifiers) if is_inverted(node): diff --git a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py index 4a52cbf9..0634a5f6 100644 --- a/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py +++ b/test/unit_tests/braket/default_simulator/openqasm/test_interpreter.py @@ -1978,7 +1978,6 @@ def test_noise(): ( "const int x = 4;", "qubit[2] q; h q[0:1];", - "gphase(0.15);", "gate my_x q { x q; }", "qubit[2] q; ctrl @ x q[0], q[1];", "qubit q; if (1) { x q; }",