From b775cf7e7d8ae50041e5ce74f89b6c0cde1a3d49 Mon Sep 17 00:00:00 2001 From: Bhargav Chickmagalur Nanjundappa Date: Mon, 1 Jul 2024 15:35:33 -0400 Subject: [PATCH 1/6] Support basic single qubit controlled gates - The single controlled gate sets are supported but requires a slight modification - The multicontrolled gates can be considered in future versions --- pytket/extensions/pyquil/pyquil_convert.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pytket/extensions/pyquil/pyquil_convert.py b/pytket/extensions/pyquil/pyquil_convert.py index ad76d8f..8adc023 100644 --- a/pytket/extensions/pyquil/pyquil_convert.py +++ b/pytket/extensions/pyquil/pyquil_convert.py @@ -71,11 +71,16 @@ "PHASE": OpType.U1, "SWAP": OpType.SWAP, "XY": OpType.ISWAP, + "CH": OpType.CH, + "CY": OpType.CY, } _known_quil_gate_rev = {v: k for k, v in _known_quil_gate.items()} +# Gates with single control +_single_control_gates = ["CH", "CY"] + def param_to_pyquil(p: Union[float, Expr]) -> Union[float, Expression]: ppi = p * pi @@ -299,7 +304,11 @@ def tk_to_pyquil( "Cannot convert tket Op to pyQuil gate: " + op.get_name() ) from error params = [param_to_pyquil(p) for p in op.params] - g = Gate(gatetype, params, qubits) + if gatetype in _single_control_gates: + g = Gate(gatetype[1:], params, [qubits[1]]).controlled(qubits[0]) # Gate name: X for CX + else: + g = Gate(gatetype, params, qubits) + p += g for m in measures: p += m From 0bea5f54279b9e642cdf03b6fb68225c60430641 Mon Sep 17 00:00:00 2001 From: Bhargav Chickmagalur Nanjundappa Date: Sat, 13 Jul 2024 23:00:13 -0400 Subject: [PATCH 2/6] Lint fixes --- pytket/extensions/pyquil/pyquil_convert.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pytket/extensions/pyquil/pyquil_convert.py b/pytket/extensions/pyquil/pyquil_convert.py index c6f1585..4740203 100644 --- a/pytket/extensions/pyquil/pyquil_convert.py +++ b/pytket/extensions/pyquil/pyquil_convert.py @@ -301,11 +301,13 @@ def tk_to_pyquil( "Cannot convert tket Op to pyQuil gate: " + op.get_name() ) from error params = [param_to_pyquil(p) for p in op.params] - if gatetype in _single_control_gates: - g = Gate(gatetype[1:], params, [qubits[1]]).controlled(qubits[0]) # Gate name: X for CX + if gatetype in _single_control_gates: + g = Gate(gatetype[1:], params, [qubits[1]]).controlled( + qubits[0] + ) # Gate name: X for CX else: g = Gate(gatetype, params, qubits) - + p += g for m in measures: p += m From 61f41af061cbe3e47e6cf80a00bd096300951999 Mon Sep 17 00:00:00 2001 From: Bhargav Chickmagalur Nanjundappa Date: Thu, 1 Aug 2024 14:42:25 -0400 Subject: [PATCH 3/6] Remove string based comparision and move to dict --- pytket/extensions/pyquil/pyquil_convert.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pytket/extensions/pyquil/pyquil_convert.py b/pytket/extensions/pyquil/pyquil_convert.py index e09186b..c811d12 100644 --- a/pytket/extensions/pyquil/pyquil_convert.py +++ b/pytket/extensions/pyquil/pyquil_convert.py @@ -78,8 +78,11 @@ _known_quil_gate_rev = {v: k for k, v in _known_quil_gate.items()} -# Gates with single control -_single_control_gates = ["CH", "CY"] +# Gates with single controlled operation +_single_control_gates = { + "CH": "H", + "CY": "Y" +} def param_to_pyquil(p: Union[float, Expr]) -> Union[float, Expression]: @@ -308,9 +311,9 @@ def tk_to_pyquil( ) from error params = [param_to_pyquil(p) for p in op.params] if gatetype in _single_control_gates: - g = Gate(gatetype[1:], params, [qubits[1]]).controlled( + g = Gate(_single_control_gates[gatetype], params, [qubits[1]]).controlled( qubits[0] - ) # Gate name: X for CX + ) else: g = Gate(gatetype, params, qubits) From f50415e215400d6eab08e8df25db7b9f9c0d930e Mon Sep 17 00:00:00 2001 From: Bhargav Chickmagalur Nanjundappa Date: Thu, 1 Aug 2024 14:43:07 -0400 Subject: [PATCH 4/6] Add test cases --- tests/pyquil_convert_test.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/pyquil_convert_test.py b/tests/pyquil_convert_test.py index cd0fc39..d01121c 100644 --- a/tests/pyquil_convert_test.py +++ b/tests/pyquil_convert_test.py @@ -46,6 +46,7 @@ from pytket.extensions.pyquil import pyquil_to_tk, tk_to_pyquil from pytket.extensions.pyquil import ForestStateBackend from pytket.passes import RemoveRedundancies +from pytket.qasm import circuit_from_qasm skip_qvm_tests = (which("docker") is None) or (platform.system() == "Windows") @@ -132,6 +133,36 @@ def test_from_tket() -> None: ) # 5 gates, 2 measures, and an initial declaration of classical register +def test_conversion_of_controlled_y() -> None: + single_controlled_gates_attributes = [ + { + "name": "Y", + "qubits": [0,1] + }, + { + "name": "H", + "qubits": [1,0] + }, + ] + c = Circuit(2,2) + c.CY(*single_controlled_gates_attributes[0]["qubits"]) + c.CH(*single_controlled_gates_attributes[1]["qubits"]) + + p = tk_to_pyquil(c) + + for i, attributes in enumerate(single_controlled_gates_attributes): + Instruction = p.instructions[i+1] + for attribute in attributes: + expected_attribute_value = attributes[attribute] + value = getattr(Instruction, attribute) + if attribute == "qubits": + for i, expected_qubit_index in enumerate(expected_attribute_value): + assert value[i].index == expected_qubit_index + else: + assert value == expected_attribute_value + + + def test_measure() -> None: p = get_test_program(True) m_map = {} From 25d104c85ceb0fb160241952dc14485605a427f3 Mon Sep 17 00:00:00 2001 From: Bhargav Chickmagalur Nanjundappa Date: Fri, 2 Aug 2024 07:58:04 -0400 Subject: [PATCH 5/6] Lint: Single qubit gates --- pytket/extensions/pyquil/pyquil_convert.py | 5 +---- tests/pyquil_convert_test.py | 17 +++++------------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/pytket/extensions/pyquil/pyquil_convert.py b/pytket/extensions/pyquil/pyquil_convert.py index c811d12..7d7e17d 100644 --- a/pytket/extensions/pyquil/pyquil_convert.py +++ b/pytket/extensions/pyquil/pyquil_convert.py @@ -79,10 +79,7 @@ _known_quil_gate_rev = {v: k for k, v in _known_quil_gate.items()} # Gates with single controlled operation -_single_control_gates = { - "CH": "H", - "CY": "Y" -} +_single_control_gates = {"CH": "H", "CY": "Y"} def param_to_pyquil(p: Union[float, Expr]) -> Union[float, Expression]: diff --git a/tests/pyquil_convert_test.py b/tests/pyquil_convert_test.py index d01121c..b15fd53 100644 --- a/tests/pyquil_convert_test.py +++ b/tests/pyquil_convert_test.py @@ -135,23 +135,17 @@ def test_from_tket() -> None: def test_conversion_of_controlled_y() -> None: single_controlled_gates_attributes = [ - { - "name": "Y", - "qubits": [0,1] - }, - { - "name": "H", - "qubits": [1,0] - }, + {"name": "Y", "qubits": [0, 1]}, + {"name": "H", "qubits": [1, 0]}, ] - c = Circuit(2,2) + c = Circuit(2, 2) c.CY(*single_controlled_gates_attributes[0]["qubits"]) c.CH(*single_controlled_gates_attributes[1]["qubits"]) p = tk_to_pyquil(c) - + for i, attributes in enumerate(single_controlled_gates_attributes): - Instruction = p.instructions[i+1] + Instruction = p.instructions[i + 1] for attribute in attributes: expected_attribute_value = attributes[attribute] value = getattr(Instruction, attribute) @@ -160,7 +154,6 @@ def test_conversion_of_controlled_y() -> None: assert value[i].index == expected_qubit_index else: assert value == expected_attribute_value - def test_measure() -> None: From 1162cc3f4988e8c55ecb88448eeacc874aedef8e Mon Sep 17 00:00:00 2001 From: cqc-melf <70640934+cqc-melf@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:29:43 +0100 Subject: [PATCH 6/6] Update tests/pyquil_convert_test.py --- tests/pyquil_convert_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/pyquil_convert_test.py b/tests/pyquil_convert_test.py index b15fd53..b9ee8ec 100644 --- a/tests/pyquil_convert_test.py +++ b/tests/pyquil_convert_test.py @@ -46,7 +46,6 @@ from pytket.extensions.pyquil import pyquil_to_tk, tk_to_pyquil from pytket.extensions.pyquil import ForestStateBackend from pytket.passes import RemoveRedundancies -from pytket.qasm import circuit_from_qasm skip_qvm_tests = (which("docker") is None) or (platform.system() == "Windows")