From 1b6c45e0efcb93a79cd7160a4ec80d839bdf3a84 Mon Sep 17 00:00:00 2001 From: Julia Plewa Date: Fri, 17 Dec 2021 15:35:31 +0100 Subject: [PATCH 1/2] Update helper methods to handle list of size one --- qiskit_ionq/helpers.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/qiskit_ionq/helpers.py b/qiskit_ionq/helpers.py index ad06ecbe..da1b8329 100644 --- a/qiskit_ionq/helpers.py +++ b/qiskit_ionq/helpers.py @@ -113,21 +113,33 @@ def qiskit_circ_to_ionq_circ(input_circuit): """Build a circuit in IonQ's instruction format from qiskit instructions. + .. NOTE:: + IonQ backends do not support multi-experiment jobs. + If ``input_circuit`` is provided as a list with more than one element + then this method will raise out with a RuntimeError. + .. ATTENTION:: This function ignores the following compiler directives: * ``barrier`` Parameters: - circ (:class:`QuantumCircuit `): A quantum circuit. + input_circuit (:class:`QuantumCircuit `): A quantum circuit. Raises: IonQGateError: If an unsupported instruction is supplied. IonQMidCircuitMeasurementError: If a mid-circuit measurement is detected. + RuntimeError: If a multi-experiment circuit was provided. Returns: list[dict]: A list of instructions in a converted dict format. int: The number of measurements. dict: The measurement map from qubit number to classical bit number. """ + + if isinstance(input_circuit, (list, tuple)): + if len(input_circuit) > 1: + raise RuntimeError("Multi-experiment jobs are not supported!") + input_circuit = input_circuit[0] + compiler_directives = ["barrier"] output_circuit = [] num_meas = 0 @@ -295,14 +307,28 @@ def decompress_metadata_string_to_dict(input_string): # pylint: disable=invalid def qiskit_to_ionq(circuit, backend_name, passed_args=None): """Convert a Qiskit circuit to a IonQ compatible dict. + .. NOTE:: + IonQ backends do not support multi-experiment jobs. + If ``circuit`` is provided as a list with more than one element + then this method will raise out with a RuntimeError. + Parameters: circuit (:class:`qiskit.circuit.QuantumCircuit`): A Qiskit quantum circuit. backend_name (str): Backend name. passed_args (dict): Dictionary containing additional passed arguments, eg. shots. + Raises: + RuntimeError: If a multi-experiment circuit was provided. + Returns: dict: A dict with IonQ API compatible values. """ + + if isinstance(circuit, (list, tuple)): + if len(circuit) > 1: + raise RuntimeError("Multi-experiment jobs are not supported!") + circuit = circuit[0] + passed_args = passed_args or {} ionq_circ, _, meas_map = qiskit_circ_to_ionq_circ(circuit) creg_sizes, clbit_labels = get_register_sizes_and_labels(circuit.cregs) From 90d3739469c6bc2c664362ee57e87d2b02acc7b7 Mon Sep 17 00:00:00 2001 From: Julia Plewa Date: Fri, 17 Dec 2021 16:07:32 +0100 Subject: [PATCH 2/2] Update helper methods tests --- test/helpers/test_gate_serialization.py | 24 +++++++++++++++ test/helpers/test_qiskit_to_ionq.py | 41 +++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/test/helpers/test_gate_serialization.py b/test/helpers/test_gate_serialization.py index 0ce0b43c..d325b385 100644 --- a/test/helpers/test_gate_serialization.py +++ b/test/helpers/test_gate_serialization.py @@ -246,3 +246,27 @@ def test_circuit_with_multiple_registers(): ] built, _, _ = qiskit_circ_to_ionq_circ(qc) assert built == expected + + +def test_simple_circuit_wrapped_in_list(): + """Test basic structure of a simple circuit when wrapped in a list.""" + qc = QuantumCircuit(1, 1) + qc.h(0) + qc.measure(0, 0) + expected = [{"gate": "h", "targets": [0]}] + built, _, _ = qiskit_circ_to_ionq_circ([qc]) + assert built == expected + + +def test_multi_circuit_list(): + """ + Test that `qiskit_circ_to_ionq_circ` raises out if more than one circuit is provided. + """ + qc0 = QuantumCircuit(1, 1) + qc0.measure(0, 0) + qc1 = QuantumCircuit(1, 1) + qc1.x(0) + qc1.measure(0, 0) + with pytest.raises(RuntimeError) as exc: + qiskit_circ_to_ionq_circ([qc0, qc1]) + assert str(exc.value) == "Multi-experiment jobs are not supported!" diff --git a/test/helpers/test_qiskit_to_ionq.py b/test/helpers/test_qiskit_to_ionq.py index ad65d227..7933950d 100644 --- a/test/helpers/test_qiskit_to_ionq.py +++ b/test/helpers/test_qiskit_to_ionq.py @@ -28,6 +28,7 @@ import json +import pytest from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister from qiskit_ionq.helpers import qiskit_to_ionq, decompress_metadata_string_to_dict @@ -101,6 +102,46 @@ def test_output_map__with_multiple_registers(simulator_backend): # pylint: disa assert actual_output_map == [0, 1, 2, 3] +def test_output_map__with_circuit_wrapped_in_list( + simulator_backend, +): # pylint: disable=invalid-name + """Test output mapping handles measurement correctly when input circuit is wrapped in a list + + Args: + simulator_backend (IonQSimulatorBackend): A simulator backend fixture. + """ + qc = QuantumCircuit(1, 1, name="test_name") + qc.measure(0, 0) + ionq_json = qiskit_to_ionq( + [qc], simulator_backend.name(), passed_args={"shots": 200, "sampler_seed": 42} + ) + actual = json.loads(ionq_json) + actual_maps = actual.pop("registers") or {} + actual_output_map = actual_maps.pop("meas_mapped") + + assert actual_output_map == [0] + + +def test_output_map__with_multiple_circuits(simulator_backend): # pylint: disable=invalid-name + """Test that `qiskit_to_ionq` raises out if more than one circuit is provided + + Args: + simulator_backend (IonQSimulatorBackend): A simulator backend fixture. + """ + qc0 = QuantumCircuit(1, 1, name="test_name_0") + qc0.measure(0, 0) + + qc1 = QuantumCircuit(1, 1, name="test_name_1") + qc1.x(0) + qc1.measure(0, 0) + + with pytest.raises(RuntimeError) as exc: + qiskit_to_ionq( + [qc0, qc1], simulator_backend.name(), passed_args={"shots": 123, "sampler_seed": 42} + ) + assert str(exc.value) == "Multi-experiment jobs are not supported!" + + def test_metadata_header__with_multiple_registers( simulator_backend, ): # pylint: disable=invalid-name