1+ import io
2+
3+ from qiskit import QuantumCircuit
4+ from qiskit .circuit import Instruction , Measure
5+ from qiskit .circuit .singleton import SingletonInstruction , stdlib_singleton_key
6+ from qiskit .circuit .exceptions import CircuitError
7+ from qiskit ._accelerate .circuit import StandardInstructionType
8+ from qiskit .qpy import dump , load
9+ from qiskit .transpiler .passes import ResetAfterMeasureSimplification
10+
11+
12+ # IDEA 1: Subclass Measure
13+ # Pitfall: can't change name
14+ class MidCircuitMeasureSubclass (Measure ):
15+ pass
16+
17+ # IDEA 1.2: Subclass Measure
18+ class CustomMeasurement (Measure ):
19+ """A custom specialized measurement."""
20+
21+ def __init__ (self , label = None ):
22+ super ().__init__ (label = label )
23+ if label :
24+ self .name = label
25+ else :
26+ self .name = "measure_2"
27+
28+
29+ # IDEA 2: Just build an instruction
30+ # Pitfall: the transpiler doesn't detect it as a measurement
31+ class MidCircuitMeasureInstruction (Instruction ):
32+ def __init__ (self , label = None ):
33+ super ().__init__ ("mid_circuit_measure" , 1 , 1 , [], label = label )
34+
35+
36+ # IDEA 3: copy Measure() definition. Works!
37+ # Pitfall:
38+ # - setting the standard instruction type like this looks a bit sketchy
39+ # - if we do this from outside qiskit (qiskit-ibm-runtime), we'd have to import
40+ # StandardInstructionType from qiskit._accelerate.circuit
41+ class NamedMeasure (SingletonInstruction ):
42+ """Quantum measurement in the computational basis."""
43+
44+ # Just force the standard instruction type?
45+ _standard_instruction_type = StandardInstructionType .Measure
46+
47+ def __init__ (self , name = "measure_2" , label = None ):
48+ """
49+ Args:
50+ label: optional string label for this instruction.
51+ """
52+ super ().__init__ (name , 1 , 1 , [], label = label )
53+
54+ def __init_subclass__ (cls , ** kwargs ):
55+ super ().__init_subclass__ (** kwargs )
56+ # Subclasses of Measure are not "standard", so we set this to None to
57+ # prevent the Rust code from treating them as such.
58+ cls ._standard_instruction_type = None
59+
60+ _singleton_lookup_key = stdlib_singleton_key ()
61+
62+ def broadcast_arguments (self , qargs , cargs ):
63+ qarg = qargs [0 ]
64+ carg = cargs [0 ]
65+
66+ if len (carg ) == len (qarg ):
67+ for qarg , carg in zip (qarg , carg ):
68+ yield [qarg ], [carg ]
69+ elif len (qarg ) == 1 and carg :
70+ for each_carg in carg :
71+ yield qarg , [each_carg ]
72+ else :
73+ raise CircuitError ("register size error" )
74+
75+ loaded = {}
76+ for cls in [CustomMeasurement ]:
77+ circ = QuantumCircuit (2 , 2 )
78+ circ .append (cls (), [0 ], [0 ])
79+ circ .append (cls ("measure_3" ), [0 ], [1 ])
80+ circ .measure_all ()
81+ print (circ .draw ())
82+
83+ with io .BytesIO () as f :
84+ dump (circ , f )
85+ f .seek (0 )
86+ loaded [str (cls )] = load (f )
87+
88+
89+ for cls , loaded_circ in loaded .items ():
90+ print (cls )
91+ print (list (loaded_circ [0 ].data ))
92+
93+ def test_bv_circuit ():
94+ """Test Bernstein Vazirani circuit with midcircuit measurement."""
95+ bitstring = "11111"
96+ qc = QuantumCircuit (2 , len (bitstring ))
97+ qc .x (1 )
98+ qc .h (1 )
99+ for idx , bit in enumerate (bitstring [::- 1 ]):
100+ qc .h (0 )
101+ if int (bit ):
102+ qc .cx (0 , 1 )
103+ qc .h (0 )
104+ qc .append (CustomMeasurement (label = "measure_3" ), [0 ], [idx ])
105+ # qc.measure(0, idx)
106+ if idx != len (bitstring ) - 1 :
107+ qc .reset (0 )
108+ # reset control
109+ qc .reset (1 )
110+ qc .x (1 )
111+ qc .h (1 )
112+ print (qc .draw ())
113+ new_qc = ResetAfterMeasureSimplification ()(qc )
114+ print (new_qc .draw ())
115+
116+ for op in new_qc .data :
117+ if op .operation .name == "reset" :
118+ print (op .qubits [0 ] == new_qc .qubits [1 ])
119+ # self.assertEqual(op.qubits[0], new_qc.qubits[1])
120+
121+ # test_bv_circuit()
0 commit comments