Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
74dfa88
Shift definition of PauliExponential to `data_structures`
Nov 28, 2025
5765674
Implement algorithm to find and then remove repeated terms in PauliPo…
keefehuang Nov 25, 2025
d0ef9f2
Introduce the new Angle enum type that allows for radians and pi4 rot…
keefehuang Nov 25, 2025
0b0c072
Implements for PauliString and PauliPolynomial.
keefehuang Nov 25, 2025
bb4a97e
Add methods for composing Clifford gadgets into CliffordTableau
keefehuang Nov 25, 2025
aeef9a5
Make imports for Sub, Add prettier
Nov 27, 2025
58b17ba
Rename from_pi4rotation functions
Nov 27, 2025
c22a622
Optimize other_pauli_string in implementation
Nov 27, 2025
871d268
Update interface for
Nov 27, 2025
6eee674
Set assert! to assert_eq
Nov 27, 2025
55811d1
Correct assert in to ensure source of panic
Nov 27, 2025
f055ec5
Improve Angle struct
Nov 27, 2025
ec9f42b
Update angle implementation to mixed arbitrary and pi4 angles
Nov 27, 2025
b56a65c
Add new wrapper for Qiskit
Dec 23, 2025
5b47d83
Fixup
Dec 26, 2025
f264893
Implement PropagateClifford for PauliExponential
Dec 28, 2025
5d88c75
Implement full loop for qiskit to IR to qiskit
Dec 28, 2025
ce11a00
Add __init__.py into qiskit folder
Dec 28, 2025
8727918
Add test for loop
Dec 28, 2025
53b68ac
Rename op to op1 for ease of reading
Dec 28, 2025
17aa3fe
Format wrapper.rs
Jan 14, 2026
ff61d9e
Format files
Jan 14, 2026
9c54dec
Add trailing white-space
Jan 14, 2026
8d13e70
Removed unneeded copy from test_qiskit_loop
Jan 15, 2026
ad35505
Remove print statements
Jan 15, 2026
bd769ca
Set return of compose_gadget to Result
Jan 15, 2026
104c682
Include pi4 rotations in PauliPolynomial tests
Jan 15, 2026
2da3a53
Format pauli_exponential.rs
Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion synir/src/data_structures.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use crate::IndexType;
use bitvec::vec::BitVec;

pub mod angle;
mod clifford_tableau;
mod pauli_exponential;
mod pauli_polynomial;
mod pauli_string;

use bitvec::vec::BitVec;
pub use angle::Angle;
pub use clifford_tableau::CliffordTableau;
pub use pauli_exponential::PauliExponential;
pub use pauli_polynomial::PauliPolynomial;
pub use pauli_string::PauliString;

Expand Down
292 changes: 292 additions & 0 deletions synir/src/data_structures/angle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
use std::{
f64::consts::PI,
ops::{Add, AddAssign, Sub, SubAssign},
};

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Angle {
Arbitrary(f64),
Pi4Rotations(u8),
}

impl Angle {
pub fn from_angle(rad: f64) -> Self {
Angle::Arbitrary(rad)
}

pub fn from_angles(angles: &[f64]) -> Vec<Self> {
angles
.into_iter()
.map(|rad| Angle::from_angle(*rad))
.collect()
}

pub fn from_pi4_rotation(n: u8) -> Self {
Angle::Pi4Rotations(n % 8)
}

pub fn from_pi4_rotations(ns: &[u8]) -> Vec<Self> {
ns.into_iter()
.map(|n| Angle::from_pi4_rotation(*n))
.collect()
}

pub fn to_radians(&self) -> f64 {
match self {
Angle::Arbitrary(rad) => *rad,
Angle::Pi4Rotations(n) => (*n as f64) * (std::f64::consts::FRAC_PI_4),
}
}

pub fn flip(&mut self) {
match self {
Angle::Arbitrary(rad) => *rad = -*rad,
Angle::Pi4Rotations(n) => *n = (8 - *n) % 8,
}
}
}

impl AddAssign for Angle {
fn add_assign(&mut self, other: Self) {
match (self, other) {
(Angle::Arbitrary(rad1), Angle::Arbitrary(rad2)) => {
*rad1 += rad2;
}
(Angle::Pi4Rotations(n1), Angle::Pi4Rotations(n2)) => {
*n1 = (*n1 + n2) % 8;
}
(Angle::Arbitrary(rad1), Angle::Pi4Rotations(n2)) => {
*rad1 += n2 as f64 * PI / 4.0;
}
_ => panic!("Cannot add Arbitrary Angle to Pi4 rotation"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you cannot say

(Angle::Pi4Rotations(n), Angle::Arbitrary(rad)) => { *self = Angle::Pi4Rotations(rad + n as f64 * PI / 4.0);}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for subassign below

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I don't think you can do this.

}
}
}

impl SubAssign for Angle {
fn sub_assign(&mut self, other: Self) {
match (self, other) {
(Angle::Arbitrary(rad1), Angle::Arbitrary(rad2)) => {
*rad1 -= rad2;
}
(Angle::Pi4Rotations(n1), Angle::Pi4Rotations(n2)) => {
*n1 = (*n1 + (8 - n2)) % 8;
}
(Angle::Arbitrary(rad1), Angle::Pi4Rotations(n2)) => {
*rad1 -= n2 as f64 * PI / 4.0;
}
_ => panic!("Cannot subtract different types of Angles"),
}
}
}

impl Add for Angle {
type Output = Angle;

fn add(self, other: Angle) -> Angle {
match (self, other) {
(Angle::Arbitrary(rad1), Angle::Arbitrary(rad2)) => Angle::Arbitrary(rad1 + rad2),
(Angle::Pi4Rotations(n1), Angle::Pi4Rotations(n2)) => {
Angle::Pi4Rotations((n1 + n2) % 8)
}
(Angle::Arbitrary(rad1), Angle::Pi4Rotations(n2)) => {
Angle::Arbitrary(rad1 + n2 as f64 * PI / 4.0)
}
(Angle::Pi4Rotations(n1), Angle::Arbitrary(rad2)) => {
Angle::Arbitrary(rad2 + n1 as f64 * PI / 4.0)
}
}
}
}

impl Sub for Angle {
type Output = Angle;

fn sub(self, other: Angle) -> Angle {
match (self, other) {
(Angle::Arbitrary(rad1), Angle::Arbitrary(rad2)) => Angle::Arbitrary(rad1 - rad2),
(Angle::Pi4Rotations(n1), Angle::Pi4Rotations(n2)) => {
Angle::Pi4Rotations((n1 + 8 - n2) % 8)
}
(Angle::Arbitrary(rad1), Angle::Pi4Rotations(n2)) => {
Angle::Arbitrary(rad1 - n2 as f64 * PI / 4.0)
}
(Angle::Pi4Rotations(n1), Angle::Arbitrary(rad2)) => {
Angle::Arbitrary(n1 as f64 * PI / 4.0 - rad2)
}
}
}
}

#[cfg(test)]
mod tests {
use super::*;

fn check_angle_approx(angle1: Angle, angle2: Angle) -> bool {
match (angle1, angle2) {
(Angle::Arbitrary(a1), Angle::Arbitrary(a2)) => (a1 - a2).abs() < 1e-9,
(Angle::Pi4Rotations(a1), Angle::Pi4Rotations(a2)) => a1 == a2,
_ => panic!("Not defined for Arbitrary Angles and Pi4 rotations"),
}
}

#[test]
fn test_angle_simple_add() {
let n1 = 1;
let n2 = 2;

let a1 = Angle::from_pi4_rotation(n1);
let a2 = Angle::from_pi4_rotation(n2);

assert_eq!(a1 + a2, Angle::from_pi4_rotation(3));

let mut a3 = Angle::from_pi4_rotation(n1);
a3 += a2;

assert_eq!(a3, Angle::from_pi4_rotation(3));
}

#[test]
fn test_angle_overflow_add() {
let n1 = 5;
let n2 = 6;

let a1 = Angle::from_pi4_rotation(n1);
let a2 = Angle::from_pi4_rotation(n2);

assert_eq!(a1 + a2, Angle::from_pi4_rotation(3));

let mut a3 = Angle::from_pi4_rotation(n1);
a3 += a2;

assert_eq!(a3, Angle::from_pi4_rotation(3));
}

#[test]
fn test_angle_simple_sub() {
let n1 = 4;
let n2 = 2;

let a1 = Angle::from_pi4_rotation(n1);
let a2 = Angle::from_pi4_rotation(n2);

assert_eq!(a1 - a2, Angle::from_pi4_rotation(2));

let mut a3 = Angle::from_pi4_rotation(n1);
a3 -= a2;

assert_eq!(a3, Angle::from_pi4_rotation(2));
}

#[test]
fn test_angle_overflow_sub() {
let n1 = 2;
let n2 = 6;

let a1 = Angle::from_pi4_rotation(n1);
let a2 = Angle::from_pi4_rotation(n2);

assert_eq!(a1 - a2, Angle::from_pi4_rotation(4));

let mut a3 = Angle::from_pi4_rotation(n1);
a3 -= a2;

assert_eq!(a3, Angle::from_pi4_rotation(4));
}

#[test]
fn test_angle_float_simple_add() {
let n1 = 0.32;
let n2 = 0.64;

let a1 = Angle::from_angle(n1);
let a2 = Angle::from_angle(n2);

let ref_a = Angle::from_angle(0.96);

assert!(check_angle_approx(a1 + a2, ref_a));

let mut a3 = Angle::from_angle(n1);
a3 += a2;

assert!(check_angle_approx(a3, ref_a));
}

#[test]
fn test_angle_float_simple_sub() {
let n1 = 0.32;
let n2 = 0.64;

let a1 = Angle::from_angle(n1);
let a2 = Angle::from_angle(n2);

let ref_a = Angle::from_angle(-0.32);

assert!(check_angle_approx(a1 - a2, ref_a));

let mut a3 = Angle::from_angle(n1);
a3 -= a2;

assert!(check_angle_approx(a3, ref_a));
}

#[test]
fn test_angle_mixed_simple_add() {
let n1 = 0.32;
let n2 = 2;

let a1 = Angle::from_angle(n1);
let a2 = Angle::from_pi4_rotation(n2);

let ref_a = Angle::from_angle(1.8907963268);
assert!(check_angle_approx(a1 + a2, ref_a));
assert!(check_angle_approx(a2 + a1, ref_a));

let mut a3 = Angle::from_angle(n1);
a3 += a2;

assert!(check_angle_approx(a3, ref_a));
}

#[test]
#[should_panic]
fn test_angle_bad_mixed_simple_add() {
let n1 = 0.32;
let n2 = 2;

let mut a2 = Angle::from_pi4_rotation(n2);
let a3 = Angle::from_angle(n1);
a2 += a3
}

#[test]
fn test_angle_mixed_simple_sub() {
let n1 = 0.32;
let n2 = 2;

let a1 = Angle::from_angle(n1);
let a2 = Angle::from_pi4_rotation(n2);

let ref_a1 = Angle::from_angle(-1.2507963268);
let ref_a2 = Angle::from_angle(1.2507963268);

assert!(check_angle_approx(a1 - a2, ref_a1));
assert!(check_angle_approx(a2 - a1, ref_a2));

let mut a3 = Angle::from_angle(n1);
a3 -= a2;

assert!(check_angle_approx(a3, ref_a1));
}

#[test]
#[should_panic]
fn test_angle_bad_mixed_simple_sub() {
let n1 = 0.32;
let n2 = 2;

let mut a2 = Angle::from_pi4_rotation(n2);
let a3 = Angle::from_angle(n1);
a2 -= a3
}
}
Loading
Loading