Skip to content

Commit be6fca5

Browse files
committed
* Create cicuit module and circuit/library submodule
* Add MidCircuitMeasure(Instruction) to new circuit library * Add unit tests
1 parent 16d19da commit be6fca5

File tree

5 files changed

+156
-0
lines changed

5 files changed

+156
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# This code is part of Qiskit.
2+
#
3+
# (C) Copyright IBM 2025.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE.txt file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
"""Module for vendor-specific circuit objects."""
14+
15+
from .library import *
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This code is part of Qiskit.
2+
#
3+
# (C) Copyright IBM 2025.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE.txt file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
"""Module for vendor-specific instructions."""
14+
15+
16+
from .mid_circuit_measure import MidCircuitMeasure
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This code is part of Qiskit.
2+
#
3+
# (C) Copyright IBM 2025.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE.txt file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
from qiskit.circuit import Instruction
14+
15+
16+
class MidCircuitMeasure(Instruction):
17+
def __init__(self, name="measure_2", label=None):
18+
if not name.startswith("measure_"):
19+
raise ValueError(
20+
"Invalid name for mid-circuit measure instruction."
21+
"The provided name must start with `measure_`"
22+
)
23+
24+
super().__init__(name, 1, 1, [], label=label)

test/unit/circuit/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This code is part of Qiskit.
2+
#
3+
# (C) Copyright IBM 2025.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE.txt file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# This code is part of Qiskit.
2+
#
3+
# (C) Copyright IBM 2025.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE.txt file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
"""Tests for MidCircuitMeasure instruction."""
14+
15+
from qiskit import QuantumCircuit, generate_preset_pass_manager
16+
from qiskit.circuit import Instruction
17+
from qiskit.providers.fake_provider import GenericBackendV2
18+
from qiskit.transpiler.exceptions import TranspilerError
19+
20+
from qiskit_ibm_runtime.circuit import MidCircuitMeasure
21+
from qiskit_ibm_runtime.fake_provider import FakeVigoV2
22+
23+
from ...ibm_test_case import IBMTestCase
24+
25+
26+
class TestMidCircuitMeasure(IBMTestCase):
27+
"""Test MidCircuitMeasure instruction."""
28+
29+
def test_instantiation(self):
30+
"""Test default instantiation."""
31+
mcm = MidCircuitMeasure()
32+
self.assertIs(mcm.base_class, MidCircuitMeasure)
33+
self.assertIsInstance(mcm, Instruction)
34+
self.assertEqual(mcm.name, "measure_2")
35+
self.assertEqual(mcm.num_qubits, 1)
36+
self.assertEqual(mcm.num_clbits, 1)
37+
38+
def test_instantiation_name(self):
39+
"""Test instantiation with custom name."""
40+
with self.subTest("measure_3"):
41+
mcm = MidCircuitMeasure("measure_3")
42+
self.assertIs(mcm.base_class, MidCircuitMeasure)
43+
self.assertIsInstance(mcm, Instruction)
44+
self.assertEqual(mcm.name, "measure_3")
45+
self.assertEqual(mcm.num_qubits, 1)
46+
self.assertEqual(mcm.num_clbits, 1)
47+
48+
with self.subTest("measure_reset"):
49+
mcm = MidCircuitMeasure("measure_reset")
50+
self.assertIs(mcm.base_class, MidCircuitMeasure)
51+
self.assertIsInstance(mcm, Instruction)
52+
self.assertEqual(mcm.name, "measure_reset")
53+
self.assertEqual(mcm.num_qubits, 1)
54+
self.assertEqual(mcm.num_clbits, 1)
55+
56+
with self.subTest("invalid_name"):
57+
with self.assertRaises(ValueError):
58+
mcm = MidCircuitMeasure("invalid_name")
59+
60+
def test_circuit_integration(self):
61+
"""Test appending to circuit."""
62+
mcm = MidCircuitMeasure()
63+
qc = QuantumCircuit(1, 2)
64+
qc.append(mcm, [0], [0])
65+
qc.append(mcm, [0], [1])
66+
qc.reset(0)
67+
self.assertIs(qc.data[0].operation, mcm)
68+
self.assertIs(qc.data[1].operation, mcm)
69+
70+
def test_transpiler_compat_without(self):
71+
"""Test that default pass manager FAILS if measure_2 not in Target."""
72+
mcm = MidCircuitMeasure()
73+
backend = FakeVigoV2()
74+
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
75+
qc = QuantumCircuit(1, 2)
76+
qc.append(mcm, [0], [0])
77+
with self.assertRaises(TranspilerError):
78+
_ = pm.run(qc)
79+
80+
def test_transpiler_compat_with(self):
81+
"""Test that default pass manager PASSES if measure_2 is in Target
82+
and doesn't modify the instruction."""
83+
mcm = MidCircuitMeasure()
84+
backend = GenericBackendV2(num_qubits=5, seed=0)
85+
backend.target.add_instruction(mcm, {(i,): None for i in range(5)})
86+
pm = generate_preset_pass_manager(backend=backend, seed_transpiler=0)
87+
qc = QuantumCircuit(1, 2)
88+
qc.append(mcm, [0], [0])
89+
transpiled = pm.run(qc)
90+
self.assertEqual(transpiled.data[0].operation.name, "measure_2")

0 commit comments

Comments
 (0)