Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d6e74ea
add some method for visualization of tableaus and pp
tungbuidang Aug 12, 2025
6028ad2
add visualization to pauli polynomial
tungbuidang Aug 13, 2025
6427129
clean up the logic for visualization
tungbuidang Aug 18, 2025
9892c69
remove unnecessary getter setter method
tungbuidang Aug 18, 2025
64d257c
added visualization to data structure in examples folder
tungbuidang Aug 18, 2025
465b330
fix some issue from pull request comments
tungbuidang Aug 20, 2025
10137fe
fix example to fit visualization case
tungbuidang Aug 21, 2025
53e4037
fix logic to true assign to - sign and false to + sign
tungbuidang Aug 21, 2025
1dab1df
add example and test for pauli polynomial
tungbuidang Aug 21, 2025
be06cdc
clean up and add Display trait to pe
tungbuidang Aug 22, 2025
633158a
clean up and add Display trait to pe
tungbuidang Aug 22, 2025
e63f18b
remove unnecessary method, make display for pp a bit more efficient b…
tungbuidang Aug 22, 2025
5da88f3
Merge remote-tracking branch 'origin' into 41-visualization
tungbuidang Aug 27, 2025
ff9d3bc
change Display function to use pauli letter instead of to_string method
tungbuidang Aug 29, 2025
0b5d2d4
Merge remote-tracking branch 'origin' into 41-visualization
tungbuidang Sep 1, 2025
2c4bce9
changed name of examples file to better match its functionality
tungbuidang Sep 1, 2025
ffe6f30
change compose function to test if python build can pass. The compile…
tungbuidang Sep 1, 2025
8eae13b
rewrite clifford tableaus Display trait to correctly print row and co…
tungbuidang Sep 2, 2025
b739ca7
update test
tungbuidang Sep 2, 2025
d0aa460
change clifford tableau display trait to use string construction, for…
tungbuidang Sep 2, 2025
ff982f1
update test
tungbuidang Sep 2, 2025
2f9c90a
fix tableaux because French
tungbuidang Sep 2, 2025
705cf68
added new display for Pauli Exponential
tungbuidang Sep 4, 2025
f7b8a55
support multi pauli polynomials printing for pauli exponential
tungbuidang Sep 10, 2025
367d185
fix pauli exponential display to not show multiple 'QB' column
tungbuidang Sep 10, 2025
832716f
add logic to correctly format clifford tableaux for big case. Also cl…
tungbuidang Sep 10, 2025
e5694c4
support print alignment of up to 99 qubits
tungbuidang Sep 11, 2025
695551f
test print empty data structure
tungbuidang Oct 21, 2025
5d0cc53
fix for merge conlfict
tungbuidang Oct 21, 2025
1f0a1e6
swap Stabilizer/Destabilizer
tungbuidang Oct 23, 2025
f9502fe
add print empty for clifford tableau and pauli polynomial
tungbuidang Oct 23, 2025
5a2fa61
fix test to pass build
tungbuidang Oct 23, 2025
26f053c
test display fix
tungbuidang Oct 24, 2025
201ae27
added printing empty logic for all data structures
tungbuidang Oct 24, 2025
1bcbf46
add some edge case for printing empty exponential
tungbuidang Oct 24, 2025
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
107 changes: 107 additions & 0 deletions synir/examples/print_data_structure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::collections::VecDeque;

use bitvec::bitvec;
use bitvec::prelude::Lsb0;
use synir::data_structures::{CliffordTableau, PauliPolynomial, PauliString};
use synir::ir::pauli_exponential::PauliExponential;

fn main() {
// test tableaus
// Stab: ZZZ, -YIY, XIX
// Destab: -IXI, XXI, IYY
// qubit 1x: ZYI
// qubit 1z: IZZ
let pauli_1 = PauliString::from_text("ZYIIZZ");
// qubit 2x: ZIX
// qubit 2z: XII
let pauli_2 = PauliString::from_text("ZIXXII");
// qubit 3x: ZYY
// qubit 3z: IIZ
let pauli_3 = PauliString::from_text("ZYYIIZ");
// qubit 4x: ZYX
// qubit 4z: IZI
let signs = bitvec![0, 1, 0, 1, 0, 0, 1, 1];
let my_tableaux = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs);
println!("Test clifford tableaux small");
println!("{}", my_tableaux);
let big_tableaux = CliffordTableau::new(20);
println!("Test clifford tableaux big");
println!("{}", big_tableaux);

let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)];
//pauli chain IXY; XXY; YII; ZII
let pp = PauliPolynomial::from_hamiltonian(ham);
println!("Test pauli polynomial");
println!("{}", pp);

let ham1 = vec![("IZZZ", 0.3)];
let pp1 = PauliPolynomial::from_hamiltonian(ham1);
let ct = CliffordTableau::new(4);
let ham2 = vec![("XIII", 0.7)];
let pp2 = PauliPolynomial::from_hamiltonian(ham2);
let pe = PauliExponential::new(VecDeque::from([pp, pp1, pp2]), ct);

println!("Test pauli exponential");
println!("{}", pe);
print!("\n\n");
println!("Testing empty data structures");
let result = std::panic::catch_unwind(|| {
test_empty_clifford_tableau();
});
if result.is_err() {
println!("test_empty_clifford_tableau panicked");
}

println!("Next test");
let result = std::panic::catch_unwind(|| {
test_empty_pauli_polynomial();
});
if result.is_err() {
println!("test_empty_pauli_polynomial panicked");
}
println!(" Next test");

let result = std::panic::catch_unwind(|| {
test_empty_pauli_exponential();
});
if result.is_err() {
println!("test_empty_pauli_exponential panicked");
}

let result = std::panic::catch_unwind(|| {
test_pauli_exponential_with_empty_polynomial();
});
if result.is_err() {
println!("test_pauli_exponential_with_empty_polynomial panicked");
}
}

fn test_empty_clifford_tableau() {
let empty_tableau = CliffordTableau::new(0);
println!("Empty Clifford Tableau:");
println!("{}", empty_tableau);
}

fn test_empty_pauli_polynomial() {
let empty_pauli_polynomial = PauliPolynomial::empty(5);
println!("Empty Pauli Polynomial:");
println!("{}", empty_pauli_polynomial);
}

fn test_empty_pauli_exponential() {
let empty_ct = CliffordTableau::new(5);
let empty_pp = PauliPolynomial::empty(5);
let empty_pe = PauliExponential::new(VecDeque::from([]), empty_ct);
println!("Empty Pauli Exponential:");
print!("{}", empty_pe);
}

fn test_pauli_exponential_with_empty_polynomial() {
let ct = CliffordTableau::new(5);
let empty_pp = PauliPolynomial::empty(5);
let ham2 = vec![("XIIIY", 0.7)];
let pp2 = PauliPolynomial::from_hamiltonian(ham2);
let pe = PauliExponential::new(VecDeque::from([empty_pp, pp2]), ct);
println!("Pauli Exponential with empty and non-empty pp:");
print!("{}", pe);
}
124 changes: 111 additions & 13 deletions synir/src/data_structures/clifford_tableau.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::fmt;
use std::iter::zip;
use std::ops::Mul;

use crate::data_structures::PauliLetter;

use super::HasAdjoint;
use super::{
pauli_string::{cx, PauliString},
Expand Down Expand Up @@ -41,6 +43,10 @@ impl CliffordTableau {
self.size
}

pub fn signs(&self) -> &BitVec {
&self.signs
}

pub(crate) fn x_signs(&self) -> BitVec {
let n = self.size();
self.signs[0..n].to_bitvec()
Expand All @@ -59,6 +65,71 @@ impl CliffordTableau {
rhs.prepend(self)
}

pub(crate) fn get_line_string(&self, i: usize) -> String {
let number_of_column = self.pauli_columns.len();
let mut out = String::new();

//add sign for stabilizers
out.push(get_pauli_sign(self.signs[i]));
out.push(' ');

//add stabilizers pauli
for column in self.pauli_columns.iter() {
let ch = get_pauli_char(&column.pauli(i));
out.push(ch);
out.push(' ');
}

if number_of_column <= 5 {
let space_left = 12 - 2 * number_of_column;
for _ in 0..space_left {
out.push(' ');
}
}

//add separator between stabilizers and destabilizers
out.push_str("| ");

//add sign for destabilizers
out.push(get_pauli_sign(self.signs[i + self.size()]));
out.push(' ');

// add destabilizers pauli
for column in self.pauli_columns.iter() {
let ch = get_pauli_char(&column.pauli(i + self.size()));
out.push(ch);
out.push(' ');
}

//add space due to the length of "destabilizers" string
if number_of_column <= 6 {
let space_left = 10 - 2 * self.pauli_columns.len();
for _ in 0..space_left {
out.push(' ');
}
}

out.push('|');
out
}
pub(crate) fn get_first_line_string(&self) -> String {
let number_of_column = self.pauli_columns.len();
let mut out = String::new();
if number_of_column <= 5 {
out.push_str(" Destabilizers | Stabilizers |\n");
} else {
out.push_str(" Destabilizers");
for _ in 0..number_of_column - 6 {
out.push_str(" ");
}
out.push_str(" | Stabilizers");
for _ in 0..number_of_column - 5 {
out.push_str(" ");
}
out.push_str(" |\n");
}
out
}
/// Implements algorithms from https://doi.org/10.22331/q-2022-06-13-734 and Qiskit Clifford implementation
pub(crate) fn prepend(&self, lhs: &Self) -> Self {
let size = self.size();
Expand Down Expand Up @@ -299,20 +370,47 @@ impl Mul for CliffordTableau {

impl fmt::Display for CliffordTableau {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "CliffordTableau({})", self.size())?;
for pauli_column in self.pauli_columns.iter() {
writeln!(f, "{}", pauli_column)?;
}
let mut sign_str = String::new();
for bit in self.signs.iter() {
match *bit {
true => sign_str.push('-'),
false => sign_str.push('+'),
let mut out: String = String::new();
if self.pauli_columns.len() == 0 {
out.push_str("Destabilizers | Stabilizers |\n");
writeln!(f, "{}", out)?;
writeln!(f)
} else {
out.push_str(" ||");
out.push_str(&self.get_first_line_string());
write!(f, "{}", out)?;
let column0 = self.pauli_columns[0].len();
for i in 0..column0 / 2 {
let mut out = String::new();
//beginning of line string
out.push_str("QB");
out.push_str(&i.to_string());
if i < 10 {
out.push(' ');
}
out.push_str("|| ");
out.push_str(&self.get_line_string(i));
writeln!(f, "{}", out)?;
}
sign_str.push(' ')
writeln!(f)
}
sign_str.pop();
write!(f, "{}", sign_str)
}
}

pub fn get_pauli_sign(sign: bool) -> char {
if sign {
'-'
} else {
'+'
}
}

pub(crate) fn get_pauli_char(letter: &PauliLetter) -> char {
match letter {
PauliLetter::I => 'I',
PauliLetter::X => 'X',
PauliLetter::Y => 'Y',
PauliLetter::Z => 'Z',
}
}

Expand Down Expand Up @@ -1192,7 +1290,7 @@ mod tests {
let ct = setup_sample_ct();
assert_eq!(
ct.to_string(),
"CliffordTableau(3)\nZ Y I I Z Z\nZ I X X I I\nZ Y Y I I Z\n+ - + - + +"
" || Destabilizers | Stabilizers |\nQB0 || + Z Z Z | - I X I |\nQB1 || - Y I Y | + Z I I |\nQB2 || + I X Y | + Z I Z |\n\n"
);
}
}
90 changes: 89 additions & 1 deletion synir/src/data_structures/pauli_polynomial.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::iter::zip;
// use std::iter::zip;

use bitvec::vec::BitVec;
use itertools::zip_eq;
// use itertools::Itertools;
use std::fmt;
use std::{iter::zip, sync::RwLock};

use super::{pauli_string::PauliString, IndexType, MaskedPropagateClifford, PropagateClifford};

Expand Down Expand Up @@ -62,6 +65,44 @@ impl PauliPolynomial {
pub fn angle(&self, i: usize) -> Angle {
self.angles[i]
}

pub fn get_line_string(&self, i: usize) -> String {
let mut out = String::new();
if self.chains.is_empty() {
out.push_str("_ |");
return out;
} else {
let chain_str = self.chains[i].to_string();
for ch in chain_str.chars() {
out.push(ch);
if !ch.is_whitespace() {
out.push_str(" |");
}
}
}
out
}

pub fn get_first_line_string(&self) -> String {
let mut out = String::new();
if self.angles.is_empty() {
out.push_str(" None |");
} else {
for angle in self.angles.iter() {
out.push_str(&format!(" {:.3}", angle)); //force 3 decimal place for formatting
out.push_str(" |");
}
}
out
}

pub fn empty(i: usize) -> Self {
PauliPolynomial {
chains: vec![],
angles: vec![],
size: i,
}
}
}

impl PropagateClifford for PauliPolynomial {
Expand Down Expand Up @@ -160,6 +201,45 @@ impl MaskedPropagateClifford for PauliPolynomial {
self
}
}

impl fmt::Display for PauliPolynomial {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut out = String::new();
// handle empty case
if self.angles.is_empty() {
out.push_str("Angles ||");
out.push_str(&self.get_first_line_string());
out.push_str("\n");
for i in 0..self.size() {
out.push_str("QB");
out.push_str(&i.to_string());
out.push_str(" || ");
out.push_str(&self.get_line_string(i));
out.push_str("\n");
// out.push_str("_ |\n");
}
writeln!(f, "{}", out)?;
} else {
// write first line
out.push_str("Angles ||"); // I take this out from get_first_line_string because I want to reuse that function for pauli exponential
out.push_str(&self.get_first_line_string());
writeln!(f, "{}", out)?;

// write subsequent lines
let chains = self.chains();
for (i, _) in chains.iter().enumerate() {
let mut out = String::new();
out.push_str("QB");
out.push_str(&i.to_string());
out.push_str(" || ");
out.push_str(&self.get_line_string(i));
writeln!(f, "{}", out)?;
}
}
writeln!(f)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -576,4 +656,12 @@ mod tests {
};
assert_eq!(pp, pp_ref);
}
#[test]
fn test_pauli_polynomial_display() {
let pp = setup_sample_pp();
assert_eq!(
pp.to_string(),
"Angles || 0.300 | 0.700 | 0.120 |\nQB0 || I | X | Y |\nQB1 || Z | Y | X |\nQB2 || Y | I | X |\n\n"
);
}
}
Loading
Loading