From 08a15dc4ae19880533d0732d9eab14766fe9341a Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Tue, 10 Dec 2024 11:42:40 -0500 Subject: [PATCH 1/6] catch all multi target uncontrolled gates --- qiskit_ionq/helpers.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/qiskit_ionq/helpers.py b/qiskit_ionq/helpers.py index 41131aa..306879d 100644 --- a/qiskit_ionq/helpers.py +++ b/qiskit_ionq/helpers.py @@ -51,7 +51,6 @@ QuantumRegister, ClassicalRegister, ) -from qiskit.circuit.library import standard_gates as q_gates # Use this to get version instead of __version__ to avoid circular dependency. from importlib_metadata import version @@ -124,13 +123,6 @@ "sxdg": "vi", } -multi_target_uncontrolled_gates = ( - q_gates.SwapGate, - q_gates.RXXGate, - q_gates.RYYGate, - q_gates.RZZGate, -) - # https://ionq.com/docs/getting-started-with-native-gates ionq_native_basis_gates = [ "gpi", # TODO All single qubit gates can transpile into GPI/GPI2 @@ -244,7 +236,7 @@ def qiskit_circ_to_ionq_circ( converted["gate"] = instruction_name # Make sure uncontrolled multi-targets use all qargs. - if isinstance(instruction, multi_target_uncontrolled_gates): + if instruction.num_qubits > 1 and not hasattr(instruction, "num_ctrl_qubits"): converted["targets"] = [ input_circuit.qubits.index(qargs[0]), input_circuit.qubits.index(qargs[1]), From 9e374b7f85074413b2fdf1bab61cdfd923817136 Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Tue, 10 Dec 2024 12:01:12 -0500 Subject: [PATCH 2/6] handle >2 qargs --- qiskit_ionq/helpers.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/qiskit_ionq/helpers.py b/qiskit_ionq/helpers.py index 306879d..5fa8dd5 100644 --- a/qiskit_ionq/helpers.py +++ b/qiskit_ionq/helpers.py @@ -236,10 +236,9 @@ def qiskit_circ_to_ionq_circ( converted["gate"] = instruction_name # Make sure uncontrolled multi-targets use all qargs. - if instruction.num_qubits > 1 and not hasattr(instruction, "num_ctrl_qubits"): + if len(qargs) > 1 and not hasattr(instruction, "num_ctrl_qubits"): converted["targets"] = [ - input_circuit.qubits.index(qargs[0]), - input_circuit.qubits.index(qargs[1]), + input_circuit.qubits.index(qargs[i]) for i in range(len(qargs)) ] # If this is a controlled gate, make sure to set control qubits. From 533875ea1c27cc67553273b1e1992239df67eca5 Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Wed, 11 Dec 2024 12:06:39 -0500 Subject: [PATCH 3/6] add test for custom rxx gate --- qiskit_ionq/helpers.py | 4 ++-- test/helpers/test_gate_serialization.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/qiskit_ionq/helpers.py b/qiskit_ionq/helpers.py index 5fa8dd5..da77aaf 100644 --- a/qiskit_ionq/helpers.py +++ b/qiskit_ionq/helpers.py @@ -236,9 +236,9 @@ def qiskit_circ_to_ionq_circ( converted["gate"] = instruction_name # Make sure uncontrolled multi-targets use all qargs. - if len(qargs) > 1 and not hasattr(instruction, "num_ctrl_qubits"): + if instruction.num_qubits > 1 and not hasattr(instruction, "num_ctrl_qubits"): converted["targets"] = [ - input_circuit.qubits.index(qargs[i]) for i in range(len(qargs)) + input_circuit.qubits.index(qargs[i]) for i in range(instruction.num_qubits) ] # If this is a controlled gate, make sure to set control qubits. diff --git a/test/helpers/test_gate_serialization.py b/test/helpers/test_gate_serialization.py index e025156..8a4ae69 100644 --- a/test/helpers/test_gate_serialization.py +++ b/test/helpers/test_gate_serialization.py @@ -27,11 +27,13 @@ """Test the qobj_to_ionq function.""" import pytest +import numpy as np from qiskit.circuit import ( QuantumCircuit, QuantumRegister, ClassicalRegister, instruction, + Parameter, ) from qiskit.circuit.library import PauliEvolutionGate from qiskit.quantum_info import SparsePauliOp @@ -336,3 +338,25 @@ def test_circuit_with_multiple_registers(): ] built, _, _ = qiskit_circ_to_ionq_circ(qc) assert built == expected + + +def test_uncontrolled_multi_target_gates(): + """Test that multi-target gates without controls are properly serialized.""" + theta = Parameter("theta") + + mtu = QuantumCircuit(2, name="rxx") + mtu.h([0, 1]) + mtu.cx(0, 1) + mtu.rz(theta, 1) + mtu.cx(0, 1) + mtu.h([0, 1]) + mtu_gate = mtu.to_gate(parameter_map={mtu.parameters[0]: np.pi / 2}) + + qc = QuantumCircuit(2) + qc.append(mtu_gate, [0, 1]) + + expected = [ + {"gate": "xx", "targets": [0, 1], "rotation": np.pi / 2}, + ] + built, _, _ = qiskit_circ_to_ionq_circ(qc) + assert built == expected From 0255a4920db55161c0fb23b4d8ff81e9482b6706 Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Wed, 11 Dec 2024 12:50:27 -0500 Subject: [PATCH 4/6] fix linting --- qiskit_ionq/helpers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit_ionq/helpers.py b/qiskit_ionq/helpers.py index da77aaf..7db1879 100644 --- a/qiskit_ionq/helpers.py +++ b/qiskit_ionq/helpers.py @@ -238,7 +238,8 @@ def qiskit_circ_to_ionq_circ( # Make sure uncontrolled multi-targets use all qargs. if instruction.num_qubits > 1 and not hasattr(instruction, "num_ctrl_qubits"): converted["targets"] = [ - input_circuit.qubits.index(qargs[i]) for i in range(instruction.num_qubits) + input_circuit.qubits.index(qargs[i]) + for i in range(instruction.num_qubits) ] # If this is a controlled gate, make sure to set control qubits. From 74a17c58e1866470adbd0f1294867f2c2c40a095 Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Wed, 11 Dec 2024 12:53:46 -0500 Subject: [PATCH 5/6] put parameter in rz --- test/helpers/test_gate_serialization.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/helpers/test_gate_serialization.py b/test/helpers/test_gate_serialization.py index 8a4ae69..61b4e46 100644 --- a/test/helpers/test_gate_serialization.py +++ b/test/helpers/test_gate_serialization.py @@ -342,12 +342,10 @@ def test_circuit_with_multiple_registers(): def test_uncontrolled_multi_target_gates(): """Test that multi-target gates without controls are properly serialized.""" - theta = Parameter("theta") - mtu = QuantumCircuit(2, name="rxx") mtu.h([0, 1]) mtu.cx(0, 1) - mtu.rz(theta, 1) + mtu.rz(Parameter("theta"), 1) mtu.cx(0, 1) mtu.h([0, 1]) mtu_gate = mtu.to_gate(parameter_map={mtu.parameters[0]: np.pi / 2}) From f9ed8b2dd58a76c65e55c09c9033c045cca6460b Mon Sep 17 00:00:00 2001 From: Spencer Churchill Date: Wed, 11 Dec 2024 13:52:50 -0500 Subject: [PATCH 6/6] minor release fix --- qiskit_ionq/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ionq/version.py b/qiskit_ionq/version.py index 358572c..ab2e8c9 100644 --- a/qiskit_ionq/version.py +++ b/qiskit_ionq/version.py @@ -34,7 +34,7 @@ pkg_parent = pathlib.Path(__file__).parent.parent.absolute() # major, minor, patch -VERSION_INFO = ".".join(map(str, (0, 5, 11))) +VERSION_INFO = ".".join(map(str, (0, 5, 12))) def _minimal_ext_cmd(cmd: List[str]) -> bytes: