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