Skip to content
Open
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
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/circuit/library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

"""Module for vendor-specific instructions."""

from .mid_circuit_measure import MidCircuitMeasure, MidCircuitReset
from .mid_circuit_measure import MeasureReset, MidCircuitMeasure, MidCircuitReset
32 changes: 28 additions & 4 deletions qiskit_ibm_runtime/circuit/library/mid_circuit_measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ class MidCircuitMeasure(Instruction):
"""Alternative 'named' measurement definition.

This instruction implements an alternative 'named' measurement definition
(1 classical bit, 1 quantum bit), whose name can be used to map to a corresponding
(one classical bit, one quantum bit), whose name can be used to map to a corresponding
mid-circuit measurement instruction implementation on hardware.
"""

def __init__(self, name: str = "measure_2", label: str | None = None) -> None:
if not name.startswith("measure_"):
raise ValueError(
"Invalid name for mid-circuit measure instruction."
"Invalid name for mid-circuit measure instruction. "
"The provided name must start with `measure_`"
)

Expand All @@ -37,15 +37,39 @@ class MidCircuitReset(Instruction):
"""Alternative 'named' reset definition.

This instruction implements an alternative 'named' reset definition
(1 quantum bit), whose name can be used to map to a corresponding
(one quantum bit), whose name can be used to map to a corresponding
mid-circuit reset instruction implementation on hardware.
"""

def __init__(self, name: str = "reset_2", label: str | None = None) -> None:
if not name.startswith("reset_"):
raise ValueError(
"Invalid name for mid-circuit reset instruction."
"Invalid name for mid-circuit reset instruction. "
"The provided name must start with `reset_`"
)

super().__init__(name, 1, 0, [], label=label)


class MeasureReset(Instruction):
"""A reset that exposes the measurement it performs internally.

This instruction implements a reset operation whose intermediate measurement
result is captured in a classical bit, making it observable to the user.
It uses one quantum bit and one classical bit, and its name can be used to
map to a corresponding hardware-level implementation, and must start with
``measure_reset``.

The semantics are: measure the qubit into the classical bit, then
conditionally flip the qubit back to ``|0>`` — i.e., a reset whose measurement
outcome is retained.
"""

def __init__(self, name: str = "measure_reset", label: str | None = None) -> None:
if not name.startswith("measure_reset"):
raise ValueError(
"Invalid name for MeasureReset instruction. "
"The provided name must start with `measure_reset`"
)

super().__init__(name, 1, 1, [], label=label)
167 changes: 113 additions & 54 deletions test/unit/circuit/test_mid_circ_meas.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from qiskit.providers.fake_provider import GenericBackendV2
from qiskit.transpiler.exceptions import TranspilerError

from qiskit_ibm_runtime.circuit import MidCircuitMeasure, MidCircuitReset
from qiskit_ibm_runtime.circuit import MeasureReset, MidCircuitMeasure, MidCircuitReset
from qiskit_ibm_runtime.fake_provider import FakeVigoV2

from ...ibm_test_case import IBMTestCase
Expand Down Expand Up @@ -92,62 +92,121 @@ def test_transpiler_compat_with(self):
transpiled = pm.run(qc)
self.assertEqual(transpiled.data[0].operation.name, "measure_2")

class TestMidCircuitReset(IBMTestCase):
"""Test MidCircuitReset instruction."""

def test_instantiation(self):
"""Test default instantiation."""
mcr = MidCircuitReset()
class TestMidCircuitReset(IBMTestCase):
"""Test MidCircuitReset instruction."""

def test_instantiation(self):
"""Test default instantiation."""
mcr = MidCircuitReset()
self.assertIs(mcr.base_class, MidCircuitReset)
self.assertIsInstance(mcr, Instruction)
self.assertEqual(mcr.name, "reset_2")
self.assertEqual(mcr.num_qubits, 1)
self.assertEqual(mcr.num_clbits, 0)

def test_instantiation_name(self):
"""Test instantiation with custom name."""
with self.subTest("reset_3"):
mcr = MidCircuitReset("reset_3")
self.assertIs(mcr.base_class, MidCircuitReset)
self.assertIsInstance(mcr, Instruction)
self.assertEqual(mcr.name, "reset_2")
self.assertEqual(mcr.name, "reset_3")
self.assertEqual(mcr.num_qubits, 1)
self.assertEqual(mcr.num_clbits, 0)

def test_instantiation_name(self):
"""Test instantiation with custom name."""
with self.subTest("reset_3"):
mcr = MidCircuitReset("reset_3")
self.assertIs(mcr.base_class, MidCircuitReset)
self.assertIsInstance(mcr, Instruction)
self.assertEqual(mcr.name, "reset_3")
self.assertEqual(mcr.num_qubits, 1)
self.assertEqual(mcr.num_clbits, 0)

with self.subTest("invalid_name"):
with self.assertRaises(ValueError):
MidCircuitReset("invalid_name")

def test_circuit_integration(self):
"""Test appending to circuit."""
mcr = MidCircuitReset()
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
qc.append(mcr, [0])
qc.reset(0)
self.assertIs(qc.data[0].operation, mcr)
self.assertIs(qc.data[1].operation, mcr)

def test_transpiler_compat_without(self):
"""Test that default pass manager FAILS if reset_2 is not in Target."""
mcr = MidCircuitReset()
backend = FakeVigoV2()
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
with self.assertRaises(TranspilerError):
_ = pm.run(qc)

def test_transpiler_compat_with(self):
"""Test default PM passes if reset_2 is in Target.

Verifies it does not modify the instruction.
"""
mcr = MidCircuitReset()
backend = GenericBackendV2(num_qubits=5, seed=0)
backend.target.add_instruction(mcr, {(i,): None for i in range(5)})
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
transpiled = pm.run(qc)
self.assertEqual(transpiled.data[0].operation.name, "reset_2")
with self.subTest("invalid_name"):
with self.assertRaises(ValueError):
MidCircuitReset("invalid_name")

def test_circuit_integration(self):
"""Test appending to circuit."""
mcr = MidCircuitReset()
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
qc.append(mcr, [0])
qc.reset(0)
self.assertIs(qc.data[0].operation, mcr)
self.assertIs(qc.data[1].operation, mcr)

def test_transpiler_compat_without(self):
"""Test that default pass manager FAILS if reset_2 is not in Target."""
mcr = MidCircuitReset()
backend = FakeVigoV2()
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
with self.assertRaises(TranspilerError):
_ = pm.run(qc)

def test_transpiler_compat_with(self):
"""Test default PM passes if reset_2 is in Target.

Verifies it does not modify the instruction.
"""
mcr = MidCircuitReset()
backend = GenericBackendV2(num_qubits=5, seed=0)
backend.target.add_instruction(mcr, {(i,): None for i in range(5)})
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 2)
qc.append(mcr, [0])
transpiled = pm.run(qc)
self.assertEqual(transpiled.data[0].operation.name, "reset_2")


class TestMeasureReset(IBMTestCase):
"""Test MeasureReset instruction."""

def test_instantiation(self):
"""Test default instantiation."""
mr = MeasureReset()
self.assertIs(mr.base_class, MeasureReset)
self.assertIsInstance(mr, Instruction)
self.assertEqual(mr.name, "measure_reset")
self.assertEqual(mr.num_qubits, 1)
self.assertEqual(mr.num_clbits, 1)

def test_instantiation_name(self):
"""Test instantiation with custom name."""
with self.subTest("measure_reset_2"):
mr = MeasureReset("measure_reset_2")
self.assertIs(mr.base_class, MeasureReset)
self.assertIsInstance(mr, Instruction)
self.assertEqual(mr.name, "measure_reset_2")
self.assertEqual(mr.num_qubits, 1)
self.assertEqual(mr.num_clbits, 1)

with self.subTest("invalid_name"):
with self.assertRaises(ValueError):
MeasureReset("invalid_name")

def test_circuit_integration(self):
"""Test appending to circuit."""
mr = MeasureReset()
qc = QuantumCircuit(1, 1)
qc.append(mr, [0], [0])
self.assertIs(qc.data[0].operation, mr)

def test_transpiler_compat_without(self):
"""Test that default pass manager FAILS if measure_reset is not in Target."""
mr = MeasureReset()
backend = FakeVigoV2()
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 1)
qc.append(mr, [0], [0])
with self.assertRaises(TranspilerError):
_ = pm.run(qc)

def test_transpiler_compat_with(self):
"""Test default PM passes if measure_reset is in Target.

Verifies it does not modify the instruction.
"""
mr = MeasureReset()
backend = GenericBackendV2(num_qubits=5, seed=0)
backend.target.add_instruction(mr, {(i,): None for i in range(5)})
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
qc = QuantumCircuit(1, 1)
qc.append(mr, [0], [0])
transpiled = pm.run(qc)
self.assertEqual(transpiled.data[0].operation.name, "measure_reset")
Loading