Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update circuit helper methods to handle list of size one #73

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion qiskit_ionq/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <qiskit.circuit.QuantumCircuit>`): A quantum circuit.
input_circuit (:class:`QuantumCircuit <qiskit.circuit.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
Expand Down Expand Up @@ -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)
Expand Down
24 changes: 24 additions & 0 deletions test/helpers/test_gate_serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -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!"
41 changes: 41 additions & 0 deletions test/helpers/test_qiskit_to_ionq.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down