Skip to content

Commit 0d8e92f

Browse files
committed
Add local Pauli matrix helper for PauliProductRotation
1 parent bb1dad9 commit 0d8e92f

2 files changed

Lines changed: 34 additions & 52 deletions

File tree

crates/circuit/src/gate_matrix.rs

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use std::f64::consts::FRAC_1_SQRT_2;
1616
// Ensure necessary imports are present
1717
use ndarray::Array2;
1818

19-
2019
use crate::util::{
2120
C_M_ONE, C_ONE, C_ZERO, GateArray0Q, GateArray1Q, GateArray2Q, GateArray3Q, GateArray4Q, IM,
2221
M_IM, c64,
@@ -531,63 +530,55 @@ pub fn xx_plus_yy_gate(theta: f64, beta: f64) -> GateArray2Q {
531530
///
532531
/// # Returns
533532
/// Dense 2^n × 2^n complex unitary matrix as `Array2<Complex64>`
534-
pub fn pauli_product_rotation_matrix(
535-
angle: f64,
536-
z: &[bool],
537-
x: &[bool],
538-
) -> Array2<Complex64> {
539533
540-
let n = z.len();
541-
let dim = 1usize << n;
534+
pub fn pauli_zx_to_dense_matrix(z: &[bool], x: &[bool]) -> Array2<Complex64> {
535+
assert_eq!(z.len(), x.len());
542536

543537
let pauli_i = Array2::from_shape_vec(
544538
(2, 2),
545-
vec![c64(1.,0.), c64(0.,0.), c64(0.,0.), c64(1.,0.)],
546-
).unwrap();
539+
vec![c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(1., 0.)],
540+
)
541+
.unwrap();
547542
let pauli_x = Array2::from_shape_vec(
548543
(2, 2),
549-
vec![c64(0.,0.), c64(1.,0.), c64(1.,0.), c64(0.,0.)],
550-
).unwrap();
544+
vec![c64(0., 0.), c64(1., 0.), c64(1., 0.), c64(0., 0.)],
545+
)
546+
.unwrap();
551547
let pauli_y = Array2::from_shape_vec(
552548
(2, 2),
553-
vec![c64(0.,0.), c64(0.,-1.), c64(0.,1.), c64(0.,0.)],
554-
).unwrap();
549+
vec![c64(0., 0.), c64(0., -1.), c64(0., 1.), c64(0., 0.)],
550+
)
551+
.unwrap();
555552
let pauli_z = Array2::from_shape_vec(
556553
(2, 2),
557-
vec![c64(1.,0.), c64(0.,0.), c64(0.,0.), c64(-1.,0.)],
558-
).unwrap();
559-
560-
// Build full tensor product using z/x symplectic representation:
561-
// z=false x=false → I
562-
// z=false x=true → X
563-
// z=true x=true → Y
564-
// z=true x=false → Z
565-
let first = match (z[0], x[0]) {
554+
vec![c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(-1., 0.)],
555+
)
556+
.unwrap();
557+
558+
let single_pauli = |z_bit: bool, x_bit: bool| match (z_bit, x_bit) {
566559
(false, false) => pauli_i.clone(),
567-
(false, true) => pauli_x.clone(),
568-
(true, true) => pauli_y.clone(),
569-
(true, false) => pauli_z.clone(),
560+
(false, true) => pauli_x.clone(),
561+
(true, true) => pauli_y.clone(),
562+
(true, false) => pauli_z.clone(),
570563
};
571564

572-
let full_pauli = (1..n).fold(first, |acc, i| {
573-
let single = match (z[i], x[i]) {
574-
(false, false) => pauli_i.clone(),
575-
(false, true) => pauli_x.clone(),
576-
(true, true) => pauli_y.clone(),
577-
(true, false) => pauli_z.clone(),
578-
};
579-
kron(&single, &acc)
580-
});
565+
let first = single_pauli(z[0], x[0]);
581566

582-
let cos_val = (angle / 2.0).cos();
583-
let sin_val = (angle / 2.0).sin();
567+
(1..z.len()).fold(first, |acc, i| {
568+
let next = single_pauli(z[i], x[i]);
569+
kron(&next, &acc)
570+
})
571+
}
584572

585-
let identity: Array2<Complex64> = Array2::eye(dim)
586-
.mapv(|x: f64| c64(x, 0.));
573+
pub fn pauli_product_rotation_matrix(angle: f64, z: &[bool], x: &[bool]) -> Array2<Complex64> {
574+
let pauli_mat = pauli_zx_to_dense_matrix(z, x);
575+
let dim = pauli_mat.shape()[0];
576+
let identity: Array2<Complex64> = Array2::eye(dim).mapv(|v: f64| c64(v, 0.));
587577

588-
identity.mapv(|v| v * c64(cos_val, 0.))
589-
+ full_pauli.mapv(|v| v * c64(0., -sin_val))
578+
let cos_val = (angle / 2.0).cos();
579+
let sin_val = (angle / 2.0).sin();
590580

581+
identity.mapv(|v| v * c64(cos_val, 0.)) + pauli_mat.mapv(|v| v * c64(0., -sin_val))
591582
}
592583

593584
/// Kronecker (tensor) product of two complex matrices.
@@ -607,4 +598,3 @@ fn kron(a: &Array2<Complex64>, b: &Array2<Complex64>) -> Array2<Complex64> {
607598
}
608599
out
609600
}
610-

crates/circuit/src/operations.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// Any modifications or derivative works of this code must retain this
1010
// copyright notice, and modified files need to carry a notice indicating
1111
// that they have been altered from the originals.
12-
1312
use approx::relative_eq;
1413
use std::f64::consts::PI;
1514
use std::fmt::Debug;
@@ -3262,7 +3261,6 @@ impl PyInstruction {
32623261
})
32633262
}
32643263

3265-
32663264
pub fn definition(&self) -> Option<CircuitData> {
32673265
Python::attach(|py| -> Option<CircuitData> {
32683266
match self.instruction.getattr(py, intern!(py, "definition")) {
@@ -3551,7 +3549,6 @@ pub struct PauliProductRotation {
35513549
pub angle: Param,
35523550
}
35533551

3554-
35553552
impl PauliProductRotation {
35563553
pub fn create_py_op(&self, py: Python, label: Option<&str>) -> PyResult<Py<PyAny>> {
35573554
let z = self.z.to_pyarray(py);
@@ -3576,20 +3573,16 @@ impl PauliProductRotation {
35763573
Param::Float(f) => f,
35773574
_ => return None,
35783575
};
3579-
let pauli_mat = gate_matrix::pauli_zx_to_dense_matrix(
3580-
&self.z,
3581-
&self.x,
3582-
);
3576+
let pauli_mat = gate_matrix::pauli_zx_to_dense_matrix(&self.z, &self.x);
35833577
let cos_val = (angle / 2.0).cos();
35843578
let sin_val = (angle / 2.0).sin();
35853579
let dim = pauli_mat.shape()[0];
35863580
let identity = Array2::<Complex64>::eye(dim);
35873581
Some(
35883582
identity.mapv(|v| Complex64::new(v.re * cos_val, 0.))
3589-
+ pauli_mat.mapv(|v| Complex64::new(0., -sin_val) * v)
3583+
+ pauli_mat.mapv(|v| Complex64::new(0., -sin_val) * v),
35903584
)
35913585
}
3592-
35933586
}
35943587

35953588
impl Operation for PauliProductRotation {
@@ -3614,7 +3607,6 @@ impl Operation for PauliProductRotation {
36143607
}
36153608
}
36163609

3617-
36183610
impl PartialEq for PauliProductRotation {
36193611
fn eq(&self, other: &Self) -> bool {
36203612
self.x == other.x

0 commit comments

Comments
 (0)