13
13
use crate :: circuit_instruction:: CircuitInstruction ;
14
14
use crate :: intern_context:: { BitType , IndexType , InternContext } ;
15
15
use crate :: SliceOrInt ;
16
+ use smallvec:: SmallVec ;
17
+
18
+ use crate :: operations:: { OperationType , Param } ;
16
19
17
20
use hashbrown:: HashMap ;
18
21
use pyo3:: exceptions:: { PyIndexError , PyKeyError , PyRuntimeError , PyValueError } ;
@@ -25,11 +28,16 @@ use std::hash::{Hash, Hasher};
25
28
#[ derive( Clone , Debug ) ]
26
29
struct PackedInstruction {
27
30
/// The Python-side operation instance.
28
- op : PyObject ,
31
+ op : OperationType ,
29
32
/// The index under which the interner has stored `qubits`.
30
33
qubits_id : IndexType ,
31
34
/// The index under which the interner has stored `clbits`.
32
35
clbits_id : IndexType ,
36
+ params : Option < SmallVec < [ Param ; 3 ] > > ,
37
+ label : Option < String > ,
38
+ duration : Option < PyObject > ,
39
+ unit : Option < String > ,
40
+ condition : Option < PyObject > ,
33
41
}
34
42
35
43
/// Private wrapper for Python-side Bit instances that implements
@@ -154,6 +162,71 @@ pub struct CircuitData {
154
162
clbits : Py < PyList > ,
155
163
}
156
164
165
+ impl CircuitData {
166
+ /// A helper method to build a new CircuitData from an owned definition
167
+ /// as a slice of OperationType, parameters, and qubits.
168
+ pub fn build_new_from (
169
+ py : Python ,
170
+ num_qubits : usize ,
171
+ num_clbits : usize ,
172
+ instructions : & [ ( OperationType , & [ Param ] , & [ u32 ] ) ] ,
173
+ ) -> PyResult < Self > {
174
+ let mut res = CircuitData {
175
+ data : Vec :: with_capacity ( instructions. len ( ) ) ,
176
+ intern_context : InternContext :: new ( ) ,
177
+ qubits_native : Vec :: with_capacity ( num_qubits) ,
178
+ clbits_native : Vec :: with_capacity ( num_clbits) ,
179
+ qubit_indices_native : HashMap :: with_capacity ( num_qubits) ,
180
+ clbit_indices_native : HashMap :: with_capacity ( num_clbits) ,
181
+ qubits : PyList :: empty_bound ( py) . unbind ( ) ,
182
+ clbits : PyList :: empty_bound ( py) . unbind ( ) ,
183
+ } ;
184
+ if num_qubits > 0 {
185
+ let qubit_mod = py. import_bound ( "qiskit.circuit.quantumregister" ) ?;
186
+ let qubit_cls = qubit_mod. getattr ( "Qubit" ) ?;
187
+ for _i in 0 ..num_qubits {
188
+ let bit = qubit_cls. call0 ( ) ?;
189
+ res. add_qubit ( py, & bit, true ) ?;
190
+ }
191
+ }
192
+ if num_clbits > 0 {
193
+ let clbit_mod = py. import_bound ( "qiskit.circuit.classicalregister" ) ?;
194
+ let clbit_cls = clbit_mod. getattr ( "Clbit" ) ?;
195
+ for _i in 0 ..num_clbits {
196
+ let bit = clbit_cls. call0 ( ) ?;
197
+ res. add_clbit ( py, & bit, true ) ?;
198
+ }
199
+ }
200
+ for ( operation, params, qargs) in instructions {
201
+ let qubits = PyTuple :: new_bound (
202
+ py,
203
+ qargs
204
+ . iter ( )
205
+ . map ( |x| res. qubits_native [ * x as usize ] . clone_ref ( py) )
206
+ . collect :: < Vec < PyObject > > ( ) ,
207
+ )
208
+ . unbind ( ) ;
209
+ let empty: [ u8 ; 0 ] = [ ] ;
210
+ let clbits = PyTuple :: new_bound ( py, empty) ;
211
+ let inst = res. pack_owned (
212
+ py,
213
+ & CircuitInstruction {
214
+ operation : operation. clone ( ) ,
215
+ qubits,
216
+ clbits : clbits. into ( ) ,
217
+ params : Some ( params. iter ( ) . cloned ( ) . collect ( ) ) ,
218
+ label : None ,
219
+ duration : None ,
220
+ unit : None ,
221
+ condition : None ,
222
+ } ,
223
+ ) ?;
224
+ res. data . push ( inst) ;
225
+ }
226
+ Ok ( res)
227
+ }
228
+ }
229
+
157
230
#[ pymethods]
158
231
impl CircuitData {
159
232
#[ new]
@@ -366,7 +439,15 @@ impl CircuitData {
366
439
#[ pyo3( signature = ( func) ) ]
367
440
pub fn foreach_op ( & self , py : Python < ' _ > , func : & Bound < PyAny > ) -> PyResult < ( ) > {
368
441
for inst in self . data . iter ( ) {
369
- func. call1 ( ( inst. op . bind ( py) , ) ) ?;
442
+ match & inst. op {
443
+ OperationType :: Standard ( op) => {
444
+ let op = op. into_py ( py) ;
445
+ func. call1 ( ( op, ) )
446
+ }
447
+ OperationType :: Instruction ( op) => func. call1 ( ( op. instruction . clone_ref ( py) , ) ) ,
448
+ OperationType :: Gate ( op) => func. call1 ( ( op. gate . clone_ref ( py) , ) ) ,
449
+ OperationType :: Operation ( op) => func. call1 ( ( op. operation . clone_ref ( py) , ) ) ,
450
+ } ?;
370
451
}
371
452
Ok ( ( ) )
372
453
}
@@ -380,7 +461,15 @@ impl CircuitData {
380
461
#[ pyo3( signature = ( func) ) ]
381
462
pub fn foreach_op_indexed ( & self , py : Python < ' _ > , func : & Bound < PyAny > ) -> PyResult < ( ) > {
382
463
for ( index, inst) in self . data . iter ( ) . enumerate ( ) {
383
- func. call1 ( ( index, inst. op . bind ( py) ) ) ?;
464
+ match & inst. op {
465
+ OperationType :: Standard ( op) => {
466
+ let op = op. into_py ( py) ;
467
+ func. call1 ( ( index, op) )
468
+ }
469
+ OperationType :: Instruction ( op) => func. call1 ( ( index, op. instruction . clone_ref ( py) ) ) ,
470
+ OperationType :: Gate ( op) => func. call1 ( ( index, op. gate . clone_ref ( py) ) ) ,
471
+ OperationType :: Operation ( op) => func. call1 ( ( index, op. operation . clone_ref ( py) ) ) ,
472
+ } ?;
384
473
}
385
474
Ok ( ( ) )
386
475
}
@@ -395,7 +484,16 @@ impl CircuitData {
395
484
#[ pyo3( signature = ( func) ) ]
396
485
pub fn map_ops ( & mut self , py : Python < ' _ > , func : & Bound < PyAny > ) -> PyResult < ( ) > {
397
486
for inst in self . data . iter_mut ( ) {
398
- inst. op = func. call1 ( ( inst. op . bind ( py) , ) ) ?. into_py ( py) ;
487
+ inst. op = match & inst. op {
488
+ OperationType :: Standard ( op) => {
489
+ let op = op. into_py ( py) ;
490
+ func. call1 ( ( op, ) )
491
+ }
492
+ OperationType :: Instruction ( op) => func. call1 ( ( op. instruction . clone_ref ( py) , ) ) ,
493
+ OperationType :: Gate ( op) => func. call1 ( ( op. gate . clone_ref ( py) , ) ) ,
494
+ OperationType :: Operation ( op) => func. call1 ( ( op. operation . clone_ref ( py) , ) ) ,
495
+ } ?
496
+ . extract ( ) ?;
399
497
}
400
498
Ok ( ( ) )
401
499
}
@@ -666,9 +764,14 @@ impl CircuitData {
666
764
. collect :: < PyResult < Vec < BitType > > > ( ) ?;
667
765
668
766
self . data . push ( PackedInstruction {
669
- op : inst. op . clone_ref ( py ) ,
767
+ op : inst. op . clone ( ) ,
670
768
qubits_id : self . intern_context . intern ( qubits) ?,
671
769
clbits_id : self . intern_context . intern ( clbits) ?,
770
+ params : inst. params . clone ( ) ,
771
+ label : inst. label . clone ( ) ,
772
+ duration : inst. duration . clone ( ) ,
773
+ unit : inst. unit . clone ( ) ,
774
+ condition : inst. condition . clone ( ) ,
672
775
} ) ;
673
776
}
674
777
return Ok ( ( ) ) ;
@@ -720,7 +823,7 @@ impl CircuitData {
720
823
721
824
fn __traverse__ ( & self , visit : PyVisit < ' _ > ) -> Result < ( ) , PyTraverseError > {
722
825
for packed in self . data . iter ( ) {
723
- visit. call ( & packed. op ) ?;
826
+ visit. call ( & packed. duration ) ?;
724
827
}
725
828
for bit in self . qubits_native . iter ( ) . chain ( self . clbits_native . iter ( ) ) {
726
829
visit. call ( bit) ?;
@@ -820,17 +923,51 @@ impl CircuitData {
820
923
self . intern_context . intern ( args)
821
924
} ;
822
925
Ok ( PackedInstruction {
823
- op : inst. operation . clone_ref ( py) ,
926
+ op : inst. operation . clone ( ) ,
927
+ qubits_id : interned_bits ( & self . qubit_indices_native , inst. qubits . bind ( py) ) ?,
928
+ clbits_id : interned_bits ( & self . clbit_indices_native , inst. clbits . bind ( py) ) ?,
929
+ params : inst. params . clone ( ) ,
930
+ label : inst. label . clone ( ) ,
931
+ duration : inst. duration . clone ( ) ,
932
+ unit : inst. unit . clone ( ) ,
933
+ condition : inst. condition . clone ( ) ,
934
+ } )
935
+ }
936
+
937
+ fn pack_owned ( & mut self , py : Python , inst : & CircuitInstruction ) -> PyResult < PackedInstruction > {
938
+ let mut interned_bits =
939
+ |indices : & HashMap < BitAsKey , BitType > , bits : & Bound < PyTuple > | -> PyResult < IndexType > {
940
+ let args = bits
941
+ . into_iter ( )
942
+ . map ( |b| {
943
+ let key = BitAsKey :: new ( & b) ?;
944
+ indices. get ( & key) . copied ( ) . ok_or_else ( || {
945
+ PyKeyError :: new_err ( format ! (
946
+ "Bit {:?} has not been added to this circuit." ,
947
+ b
948
+ ) )
949
+ } )
950
+ } )
951
+ . collect :: < PyResult < Vec < BitType > > > ( ) ?;
952
+ self . intern_context . intern ( args)
953
+ } ;
954
+ Ok ( PackedInstruction {
955
+ op : inst. operation . clone ( ) ,
824
956
qubits_id : interned_bits ( & self . qubit_indices_native , inst. qubits . bind ( py) ) ?,
825
957
clbits_id : interned_bits ( & self . clbit_indices_native , inst. clbits . bind ( py) ) ?,
958
+ params : inst. params . clone ( ) ,
959
+ label : inst. label . clone ( ) ,
960
+ duration : inst. duration . clone ( ) ,
961
+ unit : inst. unit . clone ( ) ,
962
+ condition : inst. condition . clone ( ) ,
826
963
} )
827
964
}
828
965
829
966
fn unpack ( & self , py : Python < ' _ > , inst : & PackedInstruction ) -> PyResult < Py < CircuitInstruction > > {
830
967
Py :: new (
831
968
py,
832
969
CircuitInstruction {
833
- operation : inst. op . clone_ref ( py ) ,
970
+ operation : inst. op . clone ( ) ,
834
971
qubits : PyTuple :: new_bound (
835
972
py,
836
973
self . intern_context
@@ -849,6 +986,11 @@ impl CircuitData {
849
986
. collect :: < Vec < _ > > ( ) ,
850
987
)
851
988
. unbind ( ) ,
989
+ params : inst. params . clone ( ) ,
990
+ label : inst. label . clone ( ) ,
991
+ duration : inst. duration . clone ( ) ,
992
+ unit : inst. unit . clone ( ) ,
993
+ condition : inst. condition . clone ( ) ,
852
994
} ,
853
995
)
854
996
}
0 commit comments