Skip to content

Commit

Permalink
Check for non-ISA operation inside operation flow blocks (#1784)
Browse files Browse the repository at this point in the history
* check isa inside control flow operations

* add a test to the sampler

* lint

* release note

* Update qiskit_ibm_runtime/utils/utils.py

Co-authored-by: Samuele Ferracin <[email protected]>

---------

Co-authored-by: Samuele Ferracin <[email protected]>
Co-authored-by: Kevin Tian <[email protected]>
  • Loading branch information
3 people authored Jul 5, 2024
1 parent 382b85e commit 04d05ce
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 14 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ needed so that users will understand what has changed, why it changed, and how
they'll have to update their code.

Towncrier will automatically add a link to the PR or Issue number you used in
the file name once we build the relesae notes during the release.
the file name once we build the release notes during the release.

After you've finished writing your release note, you need to add the note
file to your commit with `git add` and commit them to your PR branch to make
Expand Down
41 changes: 29 additions & 12 deletions qiskit_ibm_runtime/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ def is_simulator(backend: BackendV1 | BackendV2) -> bool:
return getattr(backend, "simulator", False)


def _is_isa_circuit_helper(circuit: QuantumCircuit, target: Target) -> str:
"""
A section of is_isa_circuit, separated to allow recursive calls
within blocks of conditional operations.
"""
for instruction in circuit.data:
operation = instruction.operation

name = operation.name
qargs = tuple(circuit.find_bit(x).index for x in instruction.qubits)
if (
not target.instruction_supported(name, qargs)
and name != "barrier"
and not circuit.has_calibration_for(instruction)
):
return (
f"The instruction {name} on qubits {qargs} is not supported by the target system."
)

if isinstance(operation, ControlFlowOp):
for sub_circ in operation.blocks:
sub_string = _is_isa_circuit_helper(sub_circ, target)
if sub_string:
return sub_string

return ""


def is_isa_circuit(circuit: QuantumCircuit, target: Target) -> str:
"""Checks if the circuit is an ISA circuit, meaning that it has a layout and that it
only uses instructions that exist in the target.
Expand All @@ -64,18 +92,7 @@ def is_isa_circuit(circuit: QuantumCircuit, target: Target) -> str:
f"but the target system requires {target.num_qubits} qubits."
)

for instruction in circuit.data:
name = instruction.operation.name
qargs = tuple(circuit.find_bit(x).index for x in instruction.qubits)
if (
not target.instruction_supported(name, qargs)
and name != "barrier"
and not circuit.has_calibration_for(instruction)
):
return (
f"The instruction {name} on qubits {qargs} is not supported by the target system."
)
return ""
return _is_isa_circuit_helper(circuit, target)


def are_circuits_dynamic(circuits: List[QuantumCircuit], qasm_default: bool = True) -> bool:
Expand Down
1 change: 1 addition & 0 deletions release-notes/unreleased/1784.bug.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Every circuit is checked to be ISA compliant. As part of this check, an error is raised if instructions that are not supported by the backend are detected. Previously, a bug caused some of the instructions to be skipped (those that reside inside bodies of control flow operations). We have fixed the bug in this release.
21 changes: 21 additions & 0 deletions test/unit/test_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from qiskit.primitives.containers.estimator_pub import EstimatorPub

from qiskit_ibm_runtime import Estimator, Session, EstimatorV2, EstimatorOptions, IBMInputValueError
from qiskit_ibm_runtime.fake_provider import FakeSherbrooke

from .mock.fake_runtime_service import FakeRuntimeService
from ..ibm_test_case import IBMTestCase
Expand Down Expand Up @@ -286,3 +287,23 @@ def test_estimator_validations(self):
obs = []
with self.assertRaisesRegex(ValueError, "Empty observables array is not allowed"):
inst.run(pubs=[(circ, obs)])

def test_gate_not_in_target(self):
"""Test exception when circuits contain gates that are not basis gates"""
# pylint: disable=invalid-name,not-context-manager
backend = FakeSherbrooke()
estimator = EstimatorV2(backend=backend)
observable = SparsePauliOp("Z")

circ = QuantumCircuit(1, 1)
circ.x(0)
circ.measure(0, 0)
with circ.if_test((0, 1)):
with circ.if_test((0, 0)) as else_:
circ.x(0)
with else_:
circ.h(0)
circ.measure(0, 0)

with self.assertRaisesRegex(IBMInputValueError, " h "):
estimator.run(pubs=[(circ, observable)])
21 changes: 20 additions & 1 deletion test/unit/test_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from qiskit.primitives.containers.sampler_pub import SamplerPub
from qiskit.circuit.library import RealAmplitudes
from qiskit_ibm_runtime import Sampler, Session, SamplerV2, SamplerOptions, IBMInputValueError
from qiskit_ibm_runtime.fake_provider import FakeFractionalBackend
from qiskit_ibm_runtime.fake_provider import FakeFractionalBackend, FakeSherbrooke

from ..ibm_test_case import IBMTestCase
from ..utils import bell, MockSession, dict_paritally_equal, get_mocked_backend, transpile_pubs
Expand Down Expand Up @@ -245,3 +245,22 @@ def test_run_fractional_dynamic_mix(self, use_fractional):
inst = SamplerV2(mode=backend)
with self.assertRaises(IBMInputValueError):
inst.run([dynamic_circuit, fractional_circuit])

def test_gate_not_in_target(self):
"""Test exception when circuits contain gates that are not basis gates"""
# pylint: disable=invalid-name,not-context-manager
backend = FakeSherbrooke()
sampler = SamplerV2(backend=backend)

circ = QuantumCircuit(1, 1)
circ.x(0)
circ.measure(0, 0)
with circ.if_test((0, 1)):
with circ.if_test((0, 0)) as else_:
circ.x(0)
with else_:
circ.h(0)
circ.measure(0, 0)

with self.assertRaisesRegex(IBMInputValueError, " h "):
sampler.run(pubs=[(circ)])

0 comments on commit 04d05ce

Please sign in to comment.