@@ -18,6 +18,7 @@ use crate::bit_data::BitData;
18
18
use crate :: circuit_instruction:: {
19
19
CircuitInstruction , ExtraInstructionAttributes , OperationFromPython ,
20
20
} ;
21
+ use crate :: converters:: QuantumCircuitData ;
21
22
use crate :: dag_node:: { DAGInNode , DAGNode , DAGOpNode , DAGOutNode } ;
22
23
use crate :: dot_utils:: build_dot;
23
24
use crate :: error:: DAGCircuitError ;
@@ -6368,6 +6369,238 @@ impl DAGCircuit {
6368
6369
6369
6370
Ok ( new_nodes)
6370
6371
}
6372
+
6373
+ /// Alternative constructor to build an instance of [DAGCircuit] from a `QuantumCircuit`.
6374
+ pub ( crate ) fn from_quantum_circuit (
6375
+ py : Python ,
6376
+ qc : QuantumCircuitData ,
6377
+ qubit_order : Option < Vec < PyObject > > ,
6378
+ clbit_order : Option < Vec < PyObject > > ,
6379
+ ) -> PyResult < DAGCircuit > {
6380
+ // Extract necessary attributes
6381
+ let qc_data = qc. data ;
6382
+ let num_qubits = qc_data. num_qubits ( ) ;
6383
+ let num_clbits = qc_data. num_clbits ( ) ;
6384
+ let num_ops = qc_data. __len__ ( ) ;
6385
+ let mut num_vars = 0 ;
6386
+ if let Some ( vars) = & qc. input_vars {
6387
+ num_vars += vars. len ( ) ?;
6388
+ }
6389
+ if let Some ( vars) = & qc. captured_vars {
6390
+ num_vars += vars. len ( ) ?;
6391
+ }
6392
+ if let Some ( vars) = & qc. declared_vars {
6393
+ num_vars += vars. len ( ) ?;
6394
+ }
6395
+ let mut num_edges = 0 ;
6396
+
6397
+ // Take ownership of the interners.
6398
+ let mut qubit_interner = if qubit_order. is_some ( ) {
6399
+ IndexedInterner :: new ( )
6400
+ } else {
6401
+ qc_data. qargs_interner ( ) . clone ( )
6402
+ } ;
6403
+
6404
+ let mut clbit_interner = if clbit_order. is_some ( ) {
6405
+ IndexedInterner :: new ( )
6406
+ } else {
6407
+ qc_data. cargs_interner ( ) . clone ( )
6408
+ } ;
6409
+
6410
+ // Take ownership of the bit_data
6411
+ let mut qubit_data = if qubit_order. is_some ( ) {
6412
+ BitData :: with_capacity ( py, "qubits" . to_string ( ) , num_qubits)
6413
+ } else {
6414
+ qc_data. qubits ( ) . clone ( )
6415
+ } ;
6416
+
6417
+ let mut clbit_data = if clbit_order. is_some ( ) {
6418
+ BitData :: with_capacity ( py, "clbits" . to_string ( ) , num_clbits)
6419
+ } else {
6420
+ qc_data. clbits ( ) . clone ( )
6421
+ } ;
6422
+
6423
+ // Pre-process the instructions
6424
+ let qubit_set: Vec < Qubit > = if let Some ( qubit_ordering) = & qubit_order {
6425
+ if qubit_ordering. len ( ) != num_qubits {
6426
+ return Err ( PyValueError :: new_err (
6427
+ "'qubit_order' does not contain exactly the same qubits as the circuit" ,
6428
+ ) ) ;
6429
+ } ;
6430
+ let mut qubits = vec ! [ ] ;
6431
+ for qubit in qubit_ordering {
6432
+ let bound = qubit. bind ( py) ;
6433
+ if qubit_data. find ( bound) . is_some ( ) {
6434
+ return Err ( DAGCircuitError :: new_err ( format ! (
6435
+ "duplicate qubits {}" ,
6436
+ bound. repr( ) ?
6437
+ ) ) ) ;
6438
+ }
6439
+ // Add bit to its respective BitData and add index to qubit_set
6440
+ qubit_data. add ( py, bound, false ) ?;
6441
+ if let Some ( qubit) = qc_data. qubits ( ) . find ( bound) {
6442
+ qubits. push ( qubit) ;
6443
+ }
6444
+ }
6445
+ qubits
6446
+ } else {
6447
+ ( 0 ..num_qubits as u32 ) . map ( Qubit ) . collect ( )
6448
+ } ;
6449
+ let clbit_set: Vec < Clbit > = if let Some ( clbit_ordering) = & clbit_order {
6450
+ if clbit_ordering. len ( ) != num_clbits {
6451
+ return Err ( PyValueError :: new_err (
6452
+ "'clbit_order' does not contain exactly the same clbits as the circuit" ,
6453
+ ) ) ;
6454
+ } ;
6455
+ let mut clbits = vec ! [ ] ;
6456
+ for clbit in clbit_ordering {
6457
+ let bound = clbit. bind ( py) ;
6458
+ if clbit_data. find ( bound) . is_some ( ) {
6459
+ return Err ( DAGCircuitError :: new_err ( format ! (
6460
+ "duplicate clbits {}" ,
6461
+ bound. repr( ) ?
6462
+ ) ) ) ;
6463
+ }
6464
+ // Add bit to its respective BitData and add index to clbit_set
6465
+ clbit_data. add ( py, bound, false ) ?;
6466
+ if let Some ( clbit) = qc_data. clbits ( ) . find ( bound) {
6467
+ clbits. push ( clbit) ;
6468
+ }
6469
+ }
6470
+ clbits
6471
+ } else {
6472
+ ( 0 ..num_clbits as u32 ) . map ( Clbit ) . collect ( )
6473
+ } ;
6474
+
6475
+ // Count all input nodes in each instruction
6476
+ let instructions: Vec < PackedInstruction > = qc_data
6477
+ . iter ( )
6478
+ . cloned ( )
6479
+ . map ( |instr| -> PyResult < PackedInstruction > {
6480
+ // Re-map the qubits
6481
+ let qargs: Vec < Qubit > = qc_data. get_qargs ( instr. qubits ) . to_vec ( ) ;
6482
+ if qubit_order. is_some ( ) {
6483
+ let ordered_qargs = qargs
6484
+ . iter ( )
6485
+ . map ( |index| qubit_set[ index. 0 as usize ] )
6486
+ . collect ( ) ;
6487
+ Interner :: intern ( & mut qubit_interner, ordered_qargs) ?;
6488
+ }
6489
+ // Remap the clbits
6490
+ let cargs: Vec < Clbit > = qc_data. get_cargs ( instr. clbits ) . to_vec ( ) ;
6491
+ if clbit_order. is_some ( ) {
6492
+ let ordered_cargs = cargs
6493
+ . iter ( )
6494
+ . map ( |index| clbit_set[ index. 0 as usize ] )
6495
+ . collect ( ) ;
6496
+ Interner :: intern ( & mut clbit_interner, ordered_cargs) ?;
6497
+ }
6498
+
6499
+ num_edges += qargs. len ( ) + cargs. len ( ) ;
6500
+
6501
+ Ok ( instr)
6502
+ } )
6503
+ . collect :: < PyResult < Vec < _ > > > ( ) ?;
6504
+
6505
+ // Build DAGCircuit with capacity
6506
+ let mut new_dag = DAGCircuit :: with_capacity (
6507
+ py,
6508
+ num_qubits,
6509
+ num_clbits,
6510
+ Some ( num_ops) ,
6511
+ Some ( num_vars) ,
6512
+ Some ( num_edges) ,
6513
+ ) ?;
6514
+
6515
+ // Assign other necessary data
6516
+ new_dag. name = qc. name . map ( |ob| ob. unbind ( ) ) ;
6517
+
6518
+ // Avoid manually acquiring the GIL.
6519
+ new_dag. global_phase = match qc_data. global_phase ( ) {
6520
+ Param :: ParameterExpression ( exp) => Param :: ParameterExpression ( exp. clone_ref ( py) ) ,
6521
+ Param :: Float ( float) => Param :: Float ( * float) ,
6522
+ _ => unreachable ! ( "Incorrect parameter assigned for global phase" ) ,
6523
+ } ;
6524
+
6525
+ new_dag. calibrations = qc. calibrations ;
6526
+ new_dag. metadata = qc. metadata . map ( |meta| meta. unbind ( ) ) ;
6527
+
6528
+ // TODO: Use Qubit ordering to remap the interners and qubit
6529
+
6530
+ // Copy over all interners and registers
6531
+ new_dag. qargs_cache = qubit_interner;
6532
+ new_dag. cargs_cache = clbit_interner;
6533
+
6534
+ new_dag. qubits = qubit_data;
6535
+ new_dag. clbits = clbit_data;
6536
+
6537
+ // Re-map and add all of the qubits
6538
+ for qubit in ( 0 ..num_qubits as u32 ) . map ( Qubit ) {
6539
+ if let Some ( bit) = new_dag. qubits . get ( qubit) {
6540
+ new_dag. qubit_locations . bind ( py) . set_item (
6541
+ bit,
6542
+ BitLocations {
6543
+ index : qubit. 0 as usize ,
6544
+ registers : PyList :: empty_bound ( py) . unbind ( ) ,
6545
+ }
6546
+ . into_py ( py) ,
6547
+ ) ?;
6548
+ new_dag. add_wire ( py, Wire :: Qubit ( qubit) ) ?;
6549
+ }
6550
+ }
6551
+
6552
+ // Re-map and add all of the qubits
6553
+ for clbit in ( 0 ..num_clbits as u32 ) . map ( Clbit ) {
6554
+ if let Some ( bit) = new_dag. clbits . get ( clbit) {
6555
+ new_dag. clbit_locations . bind ( py) . set_item (
6556
+ bit,
6557
+ BitLocations {
6558
+ index : clbit. 0 as usize ,
6559
+ registers : PyList :: empty_bound ( py) . unbind ( ) ,
6560
+ }
6561
+ . into_py ( py) ,
6562
+ ) ?;
6563
+ new_dag. add_wire ( py, Wire :: Clbit ( clbit) ) ?;
6564
+ }
6565
+ }
6566
+
6567
+ if let Some ( vars) = qc. declared_vars {
6568
+ for var in vars. iter ( ) ? {
6569
+ new_dag. add_var ( py, & var?, DAGVarType :: Declare ) ?;
6570
+ }
6571
+ }
6572
+
6573
+ if let Some ( vars) = qc. input_vars {
6574
+ for var in vars. iter ( ) ? {
6575
+ new_dag. add_var ( py, & var?, DAGVarType :: Input ) ?;
6576
+ }
6577
+ }
6578
+
6579
+ if let Some ( vars) = qc. captured_vars {
6580
+ for var in vars. iter ( ) ? {
6581
+ new_dag. add_var ( py, & var?, DAGVarType :: Capture ) ?;
6582
+ }
6583
+ }
6584
+
6585
+ // Add all the registers
6586
+
6587
+ if let Some ( qregs) = qc. qregs {
6588
+ for qreg in qregs. iter ( ) {
6589
+ new_dag. add_qreg ( py, & qreg) ?;
6590
+ }
6591
+ }
6592
+
6593
+ if let Some ( cregs) = qc. cregs {
6594
+ for creg in cregs. iter ( ) {
6595
+ new_dag. add_creg ( py, & creg) ?;
6596
+ }
6597
+ }
6598
+
6599
+ // Finally add all the instructions back
6600
+ new_dag. add_from_iter ( py, instructions) ?;
6601
+
6602
+ Ok ( new_dag)
6603
+ }
6371
6604
}
6372
6605
6373
6606
/// Add to global phase. Global phase can only be Float or ParameterExpression so this
0 commit comments