@@ -14,7 +14,7 @@ use approx::{abs_diff_eq, relative_eq};
1414use num_complex:: { Complex64 , ComplexFloat } ;
1515use num_traits:: Zero ;
1616use smallvec:: { SmallVec , smallvec} ;
17- use std:: f64:: consts:: { FRAC_1_SQRT_2 , PI } ;
17+ use std:: f64:: consts:: { FRAC_1_SQRT_2 , FRAC_PI_2 , FRAC_PI_4 , PI , TAU } ;
1818
1919use ndarray:: linalg:: kron;
2020use ndarray:: prelude:: * ;
@@ -24,7 +24,9 @@ use numpy::PyReadonlyArray2;
2424use pyo3:: exceptions:: PyValueError ;
2525use pyo3:: prelude:: * ;
2626
27- use super :: common:: { DEFAULT_FIDELITY , TraceToFidelity , rx_matrix, rz_matrix, transpose_conjugate} ;
27+ use super :: common:: {
28+ DEFAULT_FIDELITY , IPZ , TraceToFidelity , rx_matrix, rz_matrix, transpose_conjugate,
29+ } ;
2830use super :: gate_sequence:: { TwoQubitGateSequence , TwoQubitSequenceVec } ;
2931use super :: weyl_decomposition:: { __num_basis_gates, _num_basis_gates, TwoQubitWeylDecomposition } ;
3032
@@ -46,11 +48,8 @@ use qiskit_circuit::operations::{Operation, OperationRef, Param, StandardGate};
4648use qiskit_circuit:: packed_instruction:: PackedOperation ;
4749use qiskit_circuit:: { NoBlocks , Qubit } ;
4850use qiskit_util:: alias:: GateArray1Q ;
49- use qiskit_util:: complex:: { C_M_ONE , C_ONE , C_ZERO , IM , M_IM , c64} ;
51+ use qiskit_util:: complex:: { C_M_ONE , C_ONE , IM , M_IM , c64} ;
5052
51- const PI2 : f64 = PI / 2. ;
52- const PI4 : f64 = PI / 4. ;
53- const TWO_PI : f64 = 2.0 * PI ;
5453// Worst case length is 5x 1q gates for each 1q decomposition + 1x 2q gate
5554// We might overallocate a bit if the euler basis is different but
5655// the worst case is just 16 extra elements with just a String and 2 smallvecs
@@ -59,7 +58,16 @@ const TWO_PI: f64 = 2.0 * PI;
5958// Python space.
6059const TWO_QUBIT_SEQUENCE_DEFAULT_CAPACITY : usize = 21 ;
6160
62- static IPZ : GateArray1Q = [ [ IM , C_ZERO ] , [ C_ZERO , M_IM ] ] ;
61+ // constant matrices
62+ static K12R_ARR : GateArray1Q = [
63+ [ c64 ( 0. , FRAC_1_SQRT_2 ) , c64 ( FRAC_1_SQRT_2 , 0. ) ] ,
64+ [ c64 ( -FRAC_1_SQRT_2 , 0. ) , c64 ( 0. , -FRAC_1_SQRT_2 ) ] ,
65+ ] ;
66+
67+ static K12L_ARR : GateArray1Q = [
68+ [ c64 ( 0.5 , 0.5 ) , c64 ( 0.5 , 0.5 ) ] ,
69+ [ c64 ( -0.5 , 0.5 ) , c64 ( 0.5 , -0.5 ) ] ,
70+ ] ;
6371
6472#[ derive( Clone , Debug ) ]
6573#[ allow( non_snake_case) ]
@@ -193,7 +201,8 @@ impl TwoQubitBasisDecomposer {
193201 } )
194202 . collect ( ) ;
195203 let mut euler_matrix_q0 = rx_matrix ( euler_q0[ 0 ] [ 1 ] ) . dot ( & rz_matrix ( euler_q0[ 0 ] [ 0 ] ) ) ;
196- euler_matrix_q0 = rz_matrix ( euler_q0[ 0 ] [ 2 ] + euler_q0[ 1 ] [ 0 ] + PI2 ) . dot ( & euler_matrix_q0) ;
204+ euler_matrix_q0 =
205+ rz_matrix ( euler_q0[ 0 ] [ 2 ] + euler_q0[ 1 ] [ 0 ] + FRAC_PI_2 ) . dot ( & euler_matrix_q0) ;
197206 self . append_1q_sequence ( & mut gates, & mut global_phase, euler_matrix_q0. view ( ) , 0 ) ;
198207 let mut euler_matrix_q1 = rz_matrix ( euler_q1[ 0 ] [ 1 ] ) . dot ( & rx_matrix ( euler_q1[ 0 ] [ 0 ] ) ) ;
199208 euler_matrix_q1 = rx_matrix ( euler_q1[ 0 ] [ 2 ] + euler_q1[ 1 ] [ 0 ] ) . dot ( & euler_matrix_q1) ;
@@ -220,10 +229,10 @@ impl TwoQubitBasisDecomposer {
220229 smallvec ! [ euler_q1[ 1 ] [ 1 ] ] ,
221230 smallvec ! [ 1 ] ,
222231 ) ) ;
223- global_phase += PI2 ;
232+ global_phase += FRAC_PI_2 ;
224233 gates. push ( ( StandardGate :: CX . into ( ) , smallvec ! [ ] , smallvec ! [ 0 , 1 ] ) ) ;
225234 let mut euler_matrix_q0 =
226- rx_matrix ( euler_q0[ 2 ] [ 1 ] ) . dot ( & rz_matrix ( euler_q0[ 1 ] [ 2 ] + euler_q0[ 2 ] [ 0 ] + PI2 ) ) ;
235+ rx_matrix ( euler_q0[ 2 ] [ 1 ] ) . dot ( & rz_matrix ( euler_q0[ 1 ] [ 2 ] + euler_q0[ 2 ] [ 0 ] + FRAC_PI_2 ) ) ;
227236 euler_matrix_q0 = rz_matrix ( euler_q0[ 2 ] [ 2 ] ) . dot ( & euler_matrix_q0) ;
228237 self . append_1q_sequence ( & mut gates, & mut global_phase, euler_matrix_q0. view ( ) , 0 ) ;
229238 let mut euler_matrix_q1 =
@@ -253,7 +262,7 @@ impl TwoQubitBasisDecomposer {
253262 let mut gates = Vec :: new ( ) ;
254263 let mut global_phase = target_decomposed. global_phase ;
255264 global_phase -= 3. * self . basis_decomposer . global_phase ;
256- global_phase = global_phase. rem_euclid ( TWO_PI ) ;
265+ global_phase = global_phase. rem_euclid ( TAU ) ;
257266 let atol = 1e-10 ; // absolute tolerance for floats
258267 // Decompose source unitaries to zxz
259268 let euler_q0: Vec < [ f64 ; 3 ] > = decomposition
@@ -287,7 +296,7 @@ impl TwoQubitBasisDecomposer {
287296 x12_phase = PI * x12. cos ( ) ;
288297 }
289298 let x02_add = x12 - euler_q0[ 1 ] [ 0 ] ;
290- let x12_is_half_pi = abs_diff_eq ! ( x12, PI2 , epsilon = atol) ;
299+ let x12_is_half_pi = abs_diff_eq ! ( x12, FRAC_PI_2 , epsilon = atol) ;
291300
292301 let mut euler_matrix_q0 = rx_matrix ( euler_q0[ 0 ] [ 1 ] ) . dot ( & rz_matrix ( euler_q0[ 0 ] [ 0 ] ) ) ;
293302 if x12_is_non_zero && x12_is_pi_mult {
@@ -330,17 +339,17 @@ impl TwoQubitBasisDecomposer {
330339 }
331340 if x12_is_half_pi {
332341 gates. push ( ( StandardGate :: SX . into ( ) , smallvec ! [ ] , smallvec ! [ 0 ] ) ) ;
333- global_phase -= PI4 ;
342+ global_phase -= FRAC_PI_4 ;
334343 } else if x12_is_non_zero && !x12_is_pi_mult {
335344 if self . pulse_optimize . is_none ( ) {
336345 self . append_1q_sequence ( & mut gates, & mut global_phase, rx_matrix ( x12) . view ( ) , 0 ) ;
337346 } else {
338347 return None ;
339348 }
340349 }
341- if abs_diff_eq ! ( euler_q1[ 1 ] [ 1 ] , PI2 , epsilon = atol) {
350+ if abs_diff_eq ! ( euler_q1[ 1 ] [ 1 ] , FRAC_PI_2 , epsilon = atol) {
342351 gates. push ( ( StandardGate :: SX . into ( ) , smallvec ! [ ] , smallvec ! [ 1 ] ) ) ;
343- global_phase -= PI4
352+ global_phase -= FRAC_PI_4
344353 } else if self . pulse_optimize . is_none ( ) {
345354 self . append_1q_sequence (
346355 & mut gates,
@@ -362,9 +371,9 @@ impl TwoQubitBasisDecomposer {
362371 smallvec ! [ euler_q0[ 2 ] [ 1 ] ] ,
363372 smallvec ! [ 0 ] ,
364373 ) ) ;
365- if abs_diff_eq ! ( euler_q1[ 2 ] [ 1 ] , PI2 , epsilon = atol) {
374+ if abs_diff_eq ! ( euler_q1[ 2 ] [ 1 ] , FRAC_PI_2 , epsilon = atol) {
366375 gates. push ( ( StandardGate :: SX . into ( ) , smallvec ! [ ] , smallvec ! [ 1 ] ) ) ;
367- global_phase -= PI4 ;
376+ global_phase -= FRAC_PI_4 ;
368377 } else if self . pulse_optimize . is_none ( ) {
369378 self . append_1q_sequence (
370379 & mut gates,
@@ -492,7 +501,7 @@ impl TwoQubitBasisDecomposer {
492501 let ipz: ArrayView2 < Complex64 > = aview2 ( & IPZ ) ;
493502 let basis_decomposer =
494503 TwoQubitWeylDecomposition :: new_inner ( gate_matrix, Some ( DEFAULT_FIDELITY ) , None ) ?;
495- let super_controlled = relative_eq ! ( basis_decomposer. a, PI4 , max_relative = 1e-09 )
504+ let super_controlled = relative_eq ! ( basis_decomposer. a, FRAC_PI_4 , max_relative = 1e-09 )
496505 && relative_eq ! ( basis_decomposer. c, 0.0 , max_relative = 1e-09 ) ;
497506
498507 // Create some useful matrices U1, U2, U3 are equivalent to the basis,
@@ -716,16 +725,6 @@ impl TwoQubitBasisDecomposer {
716725 }
717726}
718727
719- static K12R_ARR : GateArray1Q = [
720- [ c64 ( 0. , FRAC_1_SQRT_2 ) , c64 ( FRAC_1_SQRT_2 , 0. ) ] ,
721- [ c64 ( -FRAC_1_SQRT_2 , 0. ) , c64 ( 0. , -FRAC_1_SQRT_2 ) ] ,
722- ] ;
723-
724- static K12L_ARR : GateArray1Q = [
725- [ c64 ( 0.5 , 0.5 ) , c64 ( 0.5 , 0.5 ) ] ,
726- [ c64 ( -0.5 , 0.5 ) , c64 ( 0.5 , -0.5 ) ] ,
727- ] ;
728-
729728fn decomp0_inner ( target : & TwoQubitWeylDecomposition ) -> SmallVec < [ Array2 < Complex64 > ; 8 ] > {
730729 smallvec ! [ target. K1r . dot( & target. K2r ) , target. K1l . dot( & target. K2l ) , ]
731730}
@@ -794,10 +793,10 @@ impl TwoQubitBasisDecomposer {
794793 target. a . sin ( ) * target. b . sin ( ) * target. c . sin ( ) ,
795794 ) ,
796795 4. * c64 (
797- ( PI4 - target. a ) . cos ( )
796+ ( FRAC_PI_4 - target. a ) . cos ( )
798797 * ( self . basis_decomposer . b - target. b ) . cos ( )
799798 * target. c . cos ( ) ,
800- ( PI4 - target. a ) . sin ( )
799+ ( FRAC_PI_4 - target. a ) . sin ( )
801800 * ( self . basis_decomposer . b - target. b ) . sin ( )
802801 * target. c . sin ( ) ,
803802 ) ,
@@ -966,6 +965,8 @@ impl TwoQubitBasisDecomposer {
966965 }
967966}
968967
968+ /// Helper functions for two_qubit_decompose_up_to_diagonal
969+ /// Convert a 4x4 unitary matrix into a unitary matrix with determinant 1
969970fn u4_to_su4 ( u4 : ArrayView2 < Complex64 > ) -> ( Array2 < Complex64 > , f64 ) {
970971 let det_u = ndarray_to_faer ( u4) . determinant ( ) ;
971972 let phase_factor = det_u. powf ( -0.25 ) . conj ( ) ;
@@ -1036,6 +1037,7 @@ pub fn two_qubit_decompose_up_to_diagonal(
10361037 Ok ( ( real_map, circ) )
10371038}
10381039
1040+ /// Helper function for TwoQubitBasisDecomposer with rz, sx, cx gates
10391041fn compute_unitary ( sequence : & TwoQubitSequenceVec , global_phase : f64 ) -> Array2 < Complex64 > {
10401042 let identity = aview2 ( & ONE_QUBIT_IDENTITY ) ;
10411043 let phase = c64 ( 0. , global_phase) . exp ( ) ;
0 commit comments