From d6e74ea3b8f85e982676650aadfd7830c5e885b3 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 12 Aug 2025 18:12:35 +0300 Subject: [PATCH 01/32] add some method for visualization of tableaus and pp --- .gitignore | 2 + src/data_structures/clifford_tableau.rs | 58 +++++++++++++++++++++++++ src/data_structures/pauli_polynomial.rs | 8 ++++ src/ir/pauli_exponential.rs | 16 +++++++ 4 files changed, 84 insertions(+) diff --git a/.gitignore b/.gitignore index 4a6e33d8..8e25f428 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ target/ # Ideas .idea/ .vscode/ + +src/main.rs \ No newline at end of file diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 482888a0..c29aa6b1 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -41,6 +41,14 @@ impl CliffordTableau { self.size } + pub fn pauli_column(&self, i: usize) -> &PauliString { + &self.pauli_columns[i] + } //why does column does not work and I need a new getter method ? + + pub fn signs(&self) -> &BitVec { + &self.signs + } + pub(crate) fn x_signs(&self) -> BitVec { let n = self.size(); self.signs[0..n].to_bitvec() @@ -177,6 +185,56 @@ impl CliffordTableau { .collect::>(); self.pauli_columns = sorted_pauli_columns; } + + pub fn visualize_tableaus(&self) { + println!("Clifford Tableau ({} qubits):", self.size()); + print!(" ||"); + for i in 0..self.size() { + print!(" X{} Z{}|", i + 1, i + 1); + } + println!(); + print!("+/- ||"); + for i in 0..self.signs().len() { + if self.signs().get(i).map(|b| *b) == Some(true) { + print!(" +"); + } else { + print!(" -"); + } + print!(" "); + if i % 2 != 0 { + print!("|"); + } + } + println!(); + + for i in 0..self.size() { + print!("QB{} ||", i + 1); + let column = self.pauli_column(i).to_string(); + let mut out = String::new(); + let mut count = 0; + for ch in column.chars() { + if ch != ' ' { + count += 1; + out.push(ch); + if count % 2 == 1 { + // odd + out.push(' '); + } else { + // even + out.push_str(" | "); + } + } else { + out.push(' '); + } + } + let fix = out + .replace("| I", "| I") + .replace("| Z", "| Z") + .replace("| X", "| X") + .replace("| Y", "| Y"); + println!(" {} ", fix); + } + } } impl HasAdjoint for CliffordTableau { diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index f9d005d2..249bafd7 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -68,6 +68,14 @@ impl PauliPolynomial { pub fn angle(&self, i: usize) -> Angle { self.angles.read().unwrap()[i] } + + pub fn visualize_pauli_polynomial(&self) { + println!("Pauli Polynomial size:{} ", self.size()); + let chains = self.chains(); + for i in chains { + println!("{}", i); + } + } } impl PropagateClifford for PauliPolynomial { diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index ac3824e3..45d234cd 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -27,6 +27,22 @@ impl PauliExponential { clifford_tableau, } } + //added getters for the pauli polynomials and the clifford tableau + pub fn polynomials(&self) -> &VecDeque { + &self.pauli_polynomials + } + pub fn clifford_tableau(&self) -> &CliffordTableau { + &self.clifford_tableau + } + + pub fn visualize_pauli_exponential(&self) { + println!("Clifford Tableau:"); + self.clifford_tableau.visualize_tableaus(); + println!("Pauli Polynomials:"); + for polynomial in &self.pauli_polynomials { + polynomial.visualize_pauli_polynomial(); + } + } } #[derive(Default)] From 6028ad27cd140da25e2a22d335e4b05d8ba207db Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Wed, 13 Aug 2025 15:29:26 +0300 Subject: [PATCH 02/32] add visualization to pauli polynomial --- src/data_structures/pauli_polynomial.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 249bafd7..373093bb 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -71,9 +71,27 @@ impl PauliPolynomial { pub fn visualize_pauli_polynomial(&self) { println!("Pauli Polynomial size:{} ", self.size()); + let angles = self.angles.read().unwrap(); + let string_angles = angles + .iter() + .map(|x| format!("{:.2}", x)) //force 2 decimal place for easy formatting, is it reasonable? + .collect::>() + .join(" | "); + println!("Angles | {} |", string_angles); let chains = self.chains(); - for i in chains { - println!("{}", i); + let mut index = 0; + for chain in chains { + print!("Qubit {}|", index); + let chain_str = chain.to_string(); + let mut out = String::new(); + for ch in chain_str.chars() { + out.push(ch); + if !ch.is_whitespace() { + out.push_str(" |"); //bad, hardcoded spaces + } + } + println!(" {}", out); + index += 1; } } } From 642712932e26aa68ec6e0606e26b0c628cbcdd12 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Mon, 18 Aug 2025 11:09:22 +0300 Subject: [PATCH 03/32] clean up the logic for visualization --- src/data_structures/clifford_tableau.rs | 11 ++--------- src/data_structures/pauli_polynomial.rs | 7 ++++--- src/ir/pauli_exponential.rs | 5 +++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index c29aa6b1..cbd66a81 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -217,22 +217,15 @@ impl CliffordTableau { count += 1; out.push(ch); if count % 2 == 1 { - // odd out.push(' '); } else { - // even - out.push_str(" | "); + out.push_str(" |"); } } else { out.push(' '); } } - let fix = out - .replace("| I", "| I") - .replace("| Z", "| Z") - .replace("| X", "| X") - .replace("| Y", "| Y"); - println!(" {} ", fix); + println!(" {} ", out); } } } diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 373093bb..6b622412 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -74,7 +74,7 @@ impl PauliPolynomial { let angles = self.angles.read().unwrap(); let string_angles = angles .iter() - .map(|x| format!("{:.2}", x)) //force 2 decimal place for easy formatting, is it reasonable? + .map(|x| format!("{:.3}", x)) //force 3 decimal place for easy formatting, is it reasonable? .collect::>() .join(" | "); println!("Angles | {} |", string_angles); @@ -87,13 +87,14 @@ impl PauliPolynomial { for ch in chain_str.chars() { out.push(ch); if !ch.is_whitespace() { - out.push_str(" |"); //bad, hardcoded spaces + out.push_str(" |"); //bad, hardcoded spaces. Do we want variable length ? } } println!(" {}", out); index += 1; } - } + } //visualize pauli polynomial is currently a method of the class, The formatting is + //hardcoded so it can be easily broken if input parameter changed. } impl PropagateClifford for PauliPolynomial { diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index 45d234cd..c786011d 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -36,9 +36,10 @@ impl PauliExponential { } pub fn visualize_pauli_exponential(&self) { - println!("Clifford Tableau:"); + println!("Visualizing Pauli Exponential:"); + // println!("Clifford Tableau:"); self.clifford_tableau.visualize_tableaus(); - println!("Pauli Polynomials:"); + // println!("Pauli Polynomials:"); for polynomial in &self.pauli_polynomials { polynomial.visualize_pauli_polynomial(); } From 9892c69efdac1790002b203588d6b1b9963ad0c2 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Mon, 18 Aug 2025 11:18:10 +0300 Subject: [PATCH 04/32] remove unnecessary getter setter method --- src/ir/pauli_exponential.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index c786011d..6c0711a4 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -27,13 +27,6 @@ impl PauliExponential { clifford_tableau, } } - //added getters for the pauli polynomials and the clifford tableau - pub fn polynomials(&self) -> &VecDeque { - &self.pauli_polynomials - } - pub fn clifford_tableau(&self) -> &CliffordTableau { - &self.clifford_tableau - } pub fn visualize_pauli_exponential(&self) { println!("Visualizing Pauli Exponential:"); From 64d257cd8db9eda92ef9d60a9ae8896e34e859af Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Mon, 18 Aug 2025 15:13:36 +0300 Subject: [PATCH 05/32] added visualization to data structure in examples folder --- .gitignore | 2 -- examples/plot_data_structure.rs | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 examples/plot_data_structure.rs diff --git a/.gitignore b/.gitignore index 8e25f428..4a6e33d8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,3 @@ target/ # Ideas .idea/ .vscode/ - -src/main.rs \ No newline at end of file diff --git a/examples/plot_data_structure.rs b/examples/plot_data_structure.rs new file mode 100644 index 00000000..55573f0f --- /dev/null +++ b/examples/plot_data_structure.rs @@ -0,0 +1,45 @@ +use std::collections::VecDeque; + +use bitvec::bitvec; +use bitvec::prelude::Lsb0; +use syn::data_structures::{CliffordTableau, PauliPolynomial, PauliString}; +use syn::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"); + let signs = bitvec![0, 1, 0, 1, 0, 0]; + let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); + CliffordTableau::visualize_tableaus(&my_tableaus); + + //test pauli polynomial + + let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + let pp = PauliPolynomial::from_hamiltonian(ham); + pp.visualize_pauli_polynomial(); + + // visualize_pauli_exponential_simple(&pe); + let ham = vec![("IZZZ", 0.3)]; + let pp = PauliPolynomial::from_hamiltonian(ham); + let ct = CliffordTableau::new(4); + let pe = PauliExponential::new(VecDeque::from([pp]), ct); + pe.visualize_pauli_exponential(); + + //visualize_pauli_exponential complex + let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + + let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); + let clifford_tableau = CliffordTableau::new(4); + let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); + complex_pe.visualize_pauli_exponential(); +} From 465b330215ae7e2534935a0795d20a1482a16169 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Wed, 20 Aug 2025 16:16:10 +0300 Subject: [PATCH 06/32] fix some issue from pull request comments --- src/data_structures/clifford_tableau.rs | 72 +++++++++++++++++++------ src/data_structures/pauli_polynomial.rs | 3 +- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index cbd66a81..9b99d485 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -41,10 +41,6 @@ impl CliffordTableau { self.size } - pub fn pauli_column(&self, i: usize) -> &PauliString { - &self.pauli_columns[i] - } //why does column does not work and I need a new getter method ? - pub fn signs(&self) -> &BitVec { &self.signs } @@ -209,7 +205,7 @@ impl CliffordTableau { for i in 0..self.size() { print!("QB{} ||", i + 1); - let column = self.pauli_column(i).to_string(); + let column = self.column(i).to_string(); let mut out = String::new(); let mut count = 0; for ch in column.chars() { @@ -350,22 +346,66 @@ 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('+'), +// } +// sign_str.push(' ') +// } +// sign_str.pop(); +// write!(f, "{}", sign_str) +// } +// } + 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)?; + write!(f, " ||")?; + for i in 0..self.size() { + write!(f, " X{} Z{}|", i + 1, i + 1)?; } - let mut sign_str = String::new(); - for bit in self.signs.iter() { - match *bit { - true => sign_str.push('-'), - false => sign_str.push('+'), + writeln!(f)?; + write!(f, "+/- ||")?; + for (i, sign) in self.signs().iter().enumerate() { + if *sign { + write!(f, " + ")?; + } else { + write!(f, " - ")?; + } + if i % 2 != 0 { + write!(f, "|")?; + } + } + writeln!(f)?; + + for i in 0..self.size() { + write!(f, "QB{} ||", i + 1)?; + let column = self.column(i).to_string(); + let mut out = String::new(); + let mut count = 0; + for ch in column.chars() { + if ch != ' ' { + count += 1; + out.push(ch); + if count % 2 == 1 { + out.push(' '); + } else { + out.push_str(" |"); + } + } else { + out.push(' '); + } } - sign_str.push(' ') + writeln!(f, " {} ", out)?; } - sign_str.pop(); - write!(f, "{}", sign_str) + writeln!(f) } } diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 6b622412..612ce62a 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -70,7 +70,6 @@ impl PauliPolynomial { } pub fn visualize_pauli_polynomial(&self) { - println!("Pauli Polynomial size:{} ", self.size()); let angles = self.angles.read().unwrap(); let string_angles = angles .iter() @@ -93,7 +92,7 @@ impl PauliPolynomial { println!(" {}", out); index += 1; } - } //visualize pauli polynomial is currently a method of the class, The formatting is + } //visualize pauli polynomial is currently a method of the struct, The formatting is //hardcoded so it can be easily broken if input parameter changed. } From 10137fe6ca68fcaf5d813efe316d40a0bfdf4dbe Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 21 Aug 2025 11:27:27 +0300 Subject: [PATCH 07/32] fix example to fit visualization case --- src/data_structures/clifford_tableau.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 9b99d485..ef0d640f 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -1285,7 +1285,8 @@ 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+ - + - + +" + // "CliffordTableau(3)\nZ Y I I Z Z\nZ I X X I I\nZ Y Y I I Z\n+ - + - + +" + " || X1 Z1| X2 Z2| X3 Z3|\n+/- || - + | - + | - - |\nQB1 || Z Y | I I | Z Z | \nQB2 || Z I | X X | I I | \nQB3 || Z Y | Y I | I Z | \n\n" ); } } From 53e403709484017457fa69a7049aff068e56e0c4 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 21 Aug 2025 14:30:18 +0300 Subject: [PATCH 08/32] fix logic to true assign to - sign and false to + sign --- src/data_structures/clifford_tableau.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index ef0d640f..eab9dd86 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -375,9 +375,9 @@ impl fmt::Display for CliffordTableau { write!(f, "+/- ||")?; for (i, sign) in self.signs().iter().enumerate() { if *sign { - write!(f, " + ")?; - } else { write!(f, " - ")?; + } else { + write!(f, " + ")?; } if i % 2 != 0 { write!(f, "|")?; @@ -1286,7 +1286,7 @@ mod tests { 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+ - + - + +" - " || X1 Z1| X2 Z2| X3 Z3|\n+/- || - + | - + | - - |\nQB1 || Z Y | I I | Z Z | \nQB2 || Z I | X X | I I | \nQB3 || Z Y | Y I | I Z | \n\n" + " || X1 Z1| X2 Z2| X3 Z3|\n+/- || + - | + - | + + |\nQB1 || Z Y | I I | Z Z | \nQB2 || Z I | X X | I I | \nQB3 || Z Y | Y I | I Z | \n\n" ); } } From 1dab1dfaa39f39b57df257a5e83dac62c4637034 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 21 Aug 2025 15:36:36 +0300 Subject: [PATCH 09/32] add example and test for pauli polynomial --- examples/plot_data_structure.rs | 29 +++++++++--------- src/data_structures/pauli_polynomial.rs | 39 +++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/examples/plot_data_structure.rs b/examples/plot_data_structure.rs index 55573f0f..4c9ca8bb 100644 --- a/examples/plot_data_structure.rs +++ b/examples/plot_data_structure.rs @@ -20,26 +20,27 @@ fn main() { let pauli_3 = PauliString::from_text("ZYYIIZ"); let signs = bitvec![0, 1, 0, 1, 0, 0]; let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); - CliffordTableau::visualize_tableaus(&my_tableaus); + println!("{}", my_tableaus); //test pauli polynomial let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; let pp = PauliPolynomial::from_hamiltonian(ham); - pp.visualize_pauli_polynomial(); + println!("{}", pp); + // pp.visualize_pauli_polynomial(); - // visualize_pauli_exponential_simple(&pe); - let ham = vec![("IZZZ", 0.3)]; - let pp = PauliPolynomial::from_hamiltonian(ham); - let ct = CliffordTableau::new(4); - let pe = PauliExponential::new(VecDeque::from([pp]), ct); - pe.visualize_pauli_exponential(); + // // visualize_pauli_exponential_simple(&pe); + // let ham = vec![("IZZZ", 0.3)]; + // let pp = PauliPolynomial::from_hamiltonian(ham); + // let ct = CliffordTableau::new(4); + // let pe = PauliExponential::new(VecDeque::from([pp]), ct); + // pe.visualize_pauli_exponential(); - //visualize_pauli_exponential complex - let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + // //visualize_pauli_exponential complex + // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); - let clifford_tableau = CliffordTableau::new(4); - let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); - complex_pe.visualize_pauli_exponential(); + // let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); + // let clifford_tableau = CliffordTableau::new(4); + // let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); + // complex_pe.visualize_pauli_exponential(); } diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 612ce62a..bf7d8f94 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -1,7 +1,7 @@ -use std::{iter::zip, sync::RwLock}; - use bitvec::vec::BitVec; use itertools::zip_eq; +use std::fmt; +use std::{iter::zip, sync::RwLock}; use super::{pauli_string::PauliString, IndexType, MaskedPropagateClifford, PropagateClifford}; @@ -194,6 +194,33 @@ impl MaskedPropagateClifford for PauliPolynomial { self } } + +impl fmt::Display for PauliPolynomial { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let angles = self.angles.read().unwrap(); + let string_angles = angles + .iter() + .map(|x| format!("{:.3}", x)) //force 3 decimal place for formatting + .collect::>() + .join(" | "); + writeln!(f, "Angles | {} |", string_angles)?; + let chains = self.chains(); + for (i, pauli) in chains.iter().enumerate() { + write!(f, "Qubit {}|", i)?; + let chain_str = pauli.to_string(); + let mut out = String::new(); + for ch in chain_str.chars() { + out.push(ch); + if !ch.is_whitespace() { + out.push_str(" |"); //bad, hardcoded spaces. Do we want variable length ? + } + } + writeln!(f, " {}", out)?; + } + writeln!(f) + } +} + #[cfg(test)] mod tests { use super::*; @@ -611,4 +638,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 |\nQubit 0| I | X | Y |\nQubit 1| Z | Y | X |\nQubit 2| Y | I | X |\n\n" + ); + } } From be06cdca156468c6b84f8da5016fe930a9dd8d33 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 22 Aug 2025 10:59:00 +0300 Subject: [PATCH 10/32] clean up and add Display trait to pe --- examples/plot_data_structure.rs | 21 ++++---- src/data_structures/clifford_tableau.rs | 71 ++----------------------- src/ir/pauli_exponential.rs | 18 ++++--- 3 files changed, 24 insertions(+), 86 deletions(-) diff --git a/examples/plot_data_structure.rs b/examples/plot_data_structure.rs index 4c9ca8bb..cbd8bd90 100644 --- a/examples/plot_data_structure.rs +++ b/examples/plot_data_structure.rs @@ -27,20 +27,19 @@ fn main() { let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; let pp = PauliPolynomial::from_hamiltonian(ham); println!("{}", pp); - // pp.visualize_pauli_polynomial(); // // visualize_pauli_exponential_simple(&pe); - // let ham = vec![("IZZZ", 0.3)]; - // let pp = PauliPolynomial::from_hamiltonian(ham); - // let ct = CliffordTableau::new(4); - // let pe = PauliExponential::new(VecDeque::from([pp]), ct); - // pe.visualize_pauli_exponential(); + let ham = vec![("IZZZ", 0.3)]; + let pp = PauliPolynomial::from_hamiltonian(ham); + let ct = CliffordTableau::new(4); + let pe = PauliExponential::new(VecDeque::from([pp]), ct); + println!("{}", pe); // //visualize_pauli_exponential complex - // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - // let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); - // let clifford_tableau = CliffordTableau::new(4); - // let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); - // complex_pe.visualize_pauli_exponential(); + let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); + let clifford_tableau = CliffordTableau::new(4); + let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); + println!("{}", complex_pe); } diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index eab9dd86..cf7dd303 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -181,49 +181,6 @@ impl CliffordTableau { .collect::>(); self.pauli_columns = sorted_pauli_columns; } - - pub fn visualize_tableaus(&self) { - println!("Clifford Tableau ({} qubits):", self.size()); - print!(" ||"); - for i in 0..self.size() { - print!(" X{} Z{}|", i + 1, i + 1); - } - println!(); - print!("+/- ||"); - for i in 0..self.signs().len() { - if self.signs().get(i).map(|b| *b) == Some(true) { - print!(" +"); - } else { - print!(" -"); - } - print!(" "); - if i % 2 != 0 { - print!("|"); - } - } - println!(); - - for i in 0..self.size() { - print!("QB{} ||", i + 1); - let column = self.column(i).to_string(); - let mut out = String::new(); - let mut count = 0; - for ch in column.chars() { - if ch != ' ' { - count += 1; - out.push(ch); - if count % 2 == 1 { - out.push(' '); - } else { - out.push_str(" |"); - } - } else { - out.push(' '); - } - } - println!(" {} ", out); - } - } } impl HasAdjoint for CliffordTableau { @@ -346,25 +303,6 @@ 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('+'), -// } -// sign_str.push(' ') -// } -// sign_str.pop(); -// write!(f, "{}", sign_str) -// } -// } - impl fmt::Display for CliffordTableau { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, " ||")?; @@ -385,12 +323,11 @@ impl fmt::Display for CliffordTableau { } writeln!(f)?; - for i in 0..self.size() { - write!(f, "QB{} ||", i + 1)?; - let column = self.column(i).to_string(); + for (i, column) in self.pauli_columns.iter().enumerate() { + write!(f, "QB{} ||", i)?; let mut out = String::new(); let mut count = 0; - for ch in column.chars() { + for ch in column.to_string().chars() { if ch != ' ' { count += 1; out.push(ch); @@ -1286,7 +1223,7 @@ mod tests { 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+ - + - + +" - " || X1 Z1| X2 Z2| X3 Z3|\n+/- || + - | + - | + + |\nQB1 || Z Y | I I | Z Z | \nQB2 || Z I | X X | I I | \nQB3 || Z Y | Y I | I Z | \n\n" + " || X1 Z1| X2 Z2| X3 Z3|\n+/- || + - | + - | + + |\nQB0 || Z Y | I I | Z Z | \nQB1 || Z I | X X | I I | \nQB2 || Z Y | Y I | I Z | \n\n" ); } } diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index 6c0711a4..ddc314af 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::fmt; use crate::data_structures::{CliffordTableau, HasAdjoint, PauliPolynomial}; @@ -27,18 +28,19 @@ impl PauliExponential { clifford_tableau, } } +} - pub fn visualize_pauli_exponential(&self) { - println!("Visualizing Pauli Exponential:"); - // println!("Clifford Tableau:"); - self.clifford_tableau.visualize_tableaus(); - // println!("Pauli Polynomials:"); - for polynomial in &self.pauli_polynomials { - polynomial.visualize_pauli_polynomial(); +impl fmt::Display for PauliExponential { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "Clifford Tableau: \n{}", self.clifford_tableau)?; + writeln!(f, "Pauli Polynomials:")?; + for (i, pp) in self.pauli_polynomials.iter().enumerate() { + writeln!(f, "Pauli {} ", i)?; + writeln!(f, "{}", pp)?; } + writeln!(f) } } - #[derive(Default)] pub struct PauliExponentialSynthesizer { pauli_strategy: PauliPolynomialSynthStrategy, From 633158abd184b7ffed77e4c351c69292a91004d2 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 22 Aug 2025 11:00:51 +0300 Subject: [PATCH 11/32] clean up and add Display trait to pe --- src/data_structures/clifford_tableau.rs | 1 - src/data_structures/pauli_polynomial.rs | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index cf7dd303..3f434841 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -1222,7 +1222,6 @@ 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+ - + - + +" " || X1 Z1| X2 Z2| X3 Z3|\n+/- || + - | + - | + + |\nQB0 || Z Y | I I | Z Z | \nQB1 || Z I | X X | I I | \nQB2 || Z Y | Y I | I Z | \n\n" ); } diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index bf7d8f94..af53aa8a 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -73,7 +73,7 @@ impl PauliPolynomial { let angles = self.angles.read().unwrap(); let string_angles = angles .iter() - .map(|x| format!("{:.3}", x)) //force 3 decimal place for easy formatting, is it reasonable? + .map(|x| format!("{:.3}", x)) //force 3 decimal place for easy formatting .collect::>() .join(" | "); println!("Angles | {} |", string_angles); @@ -86,14 +86,13 @@ impl PauliPolynomial { for ch in chain_str.chars() { out.push(ch); if !ch.is_whitespace() { - out.push_str(" |"); //bad, hardcoded spaces. Do we want variable length ? + out.push_str(" |"); } } println!(" {}", out); index += 1; } - } //visualize pauli polynomial is currently a method of the struct, The formatting is - //hardcoded so it can be easily broken if input parameter changed. + } } impl PropagateClifford for PauliPolynomial { From e63f18bdb09038da8e1b3c3b1d73628a6b13549a Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 22 Aug 2025 14:26:52 +0300 Subject: [PATCH 12/32] remove unnecessary method, make display for pp a bit more efficient by removing vec allocation --- src/data_structures/pauli_polynomial.rs | 29 ++----------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index af53aa8a..57a80e16 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -1,5 +1,6 @@ use bitvec::vec::BitVec; use itertools::zip_eq; +use itertools::Itertools; use std::fmt; use std::{iter::zip, sync::RwLock}; @@ -68,31 +69,6 @@ impl PauliPolynomial { pub fn angle(&self, i: usize) -> Angle { self.angles.read().unwrap()[i] } - - pub fn visualize_pauli_polynomial(&self) { - let angles = self.angles.read().unwrap(); - let string_angles = angles - .iter() - .map(|x| format!("{:.3}", x)) //force 3 decimal place for easy formatting - .collect::>() - .join(" | "); - println!("Angles | {} |", string_angles); - let chains = self.chains(); - let mut index = 0; - for chain in chains { - print!("Qubit {}|", index); - let chain_str = chain.to_string(); - let mut out = String::new(); - for ch in chain_str.chars() { - out.push(ch); - if !ch.is_whitespace() { - out.push_str(" |"); - } - } - println!(" {}", out); - index += 1; - } - } } impl PropagateClifford for PauliPolynomial { @@ -200,7 +176,6 @@ impl fmt::Display for PauliPolynomial { let string_angles = angles .iter() .map(|x| format!("{:.3}", x)) //force 3 decimal place for formatting - .collect::>() .join(" | "); writeln!(f, "Angles | {} |", string_angles)?; let chains = self.chains(); @@ -211,7 +186,7 @@ impl fmt::Display for PauliPolynomial { for ch in chain_str.chars() { out.push(ch); if !ch.is_whitespace() { - out.push_str(" |"); //bad, hardcoded spaces. Do we want variable length ? + out.push_str(" |"); } } writeln!(f, " {}", out)?; From ff9d3bcc1a474f886cba3b2d620f7124b1e0921e Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 29 Aug 2025 10:27:47 +0300 Subject: [PATCH 13/32] change Display function to use pauli letter instead of to_string method --- examples/plot_data_structure.rs | 3 +- src/data_structures/clifford_tableau.rs | 41 +++++++++++++++++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/examples/plot_data_structure.rs b/examples/plot_data_structure.rs index cbd8bd90..78ab048c 100644 --- a/examples/plot_data_structure.rs +++ b/examples/plot_data_structure.rs @@ -22,7 +22,8 @@ fn main() { let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); println!("{}", my_tableaus); - //test pauli polynomial + + // test pauli polynomial let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; let pp = PauliPolynomial::from_hamiltonian(ham); diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index d116d999..2848b677 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -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}, @@ -59,7 +61,7 @@ impl CliffordTableau { &self.pauli_columns[i] } - pub fn compose(&self, rhs: &Self) -> Self { + pub(crate) fn compose(&self, rhs: &Self) -> Self { rhs.prepend(self) } @@ -326,21 +328,36 @@ impl fmt::Display for CliffordTableau { for (i, column) in self.pauli_columns.iter().enumerate() { write!(f, "QB{} ||", i)?; let mut out = String::new(); - let mut count = 0; - for ch in column.to_string().chars() { - if ch != ' ' { - count += 1; - out.push(ch); - if count % 2 == 1 { - out.push(' '); - } else { - out.push_str(" |"); + let mut letter_count = 0; + for j in 0..column.len() { + // let letter = column.pauli(j); + match column.pauli(j) { + PauliLetter::I => { + out.push('I'); + letter_count += 1; } - } else { + PauliLetter::X => { + out.push('X'); + letter_count += 1; + } + PauliLetter::Z => { + out.push('Z'); + letter_count += 1; + } + PauliLetter::Y => { + out.push('Y'); + letter_count += 1; + } + } + if letter_count % 2 == 1 { out.push(' '); + } else { + out.push_str(" |"); } + out.push(' '); } - writeln!(f, " {} ", out)?; + out.push('\n'); + write!(f, " {}", out)?; } writeln!(f) } From 2c4bce9002d7cda0d1a6bb666ed7a55dc8ac2c39 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Mon, 1 Sep 2025 09:37:44 +0300 Subject: [PATCH 14/32] changed name of examples file to better match its functionality --- examples/{plot_data_structure.rs => print_data_structure.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{plot_data_structure.rs => print_data_structure.rs} (100%) diff --git a/examples/plot_data_structure.rs b/examples/print_data_structure.rs similarity index 100% rename from examples/plot_data_structure.rs rename to examples/print_data_structure.rs From ffe6f308303826cada288bf8e46a73e5d7fece34 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Mon, 1 Sep 2025 09:49:48 +0300 Subject: [PATCH 15/32] change compose function to test if python build can pass. The compiler complain compose is a private method --- src/data_structures/clifford_tableau.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 2848b677..824280a1 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -61,7 +61,7 @@ impl CliffordTableau { &self.pauli_columns[i] } - pub(crate) fn compose(&self, rhs: &Self) -> Self { + pub fn compose(&self, rhs: &Self) -> Self { rhs.prepend(self) } From 8eae13b23aa90e8a2335d5cc918548e10c2ab935 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 2 Sep 2025 12:44:56 +0300 Subject: [PATCH 16/32] rewrite clifford tableaus Display trait to correctly print row and column --- examples/print_data_structure.rs | 39 ++++--- src/data_structures/clifford_tableau.rs | 147 ++++++++++++++++-------- 2 files changed, 120 insertions(+), 66 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index 78ab048c..aff68df5 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -18,29 +18,32 @@ fn main() { // qubit 3x: ZYY // qubit 3z: IIZ let pauli_3 = PauliString::from_text("ZYYIIZ"); - let signs = bitvec![0, 1, 0, 1, 0, 0]; - let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); + // qubit 4x: ZYX + // qubit 4z: IZI + let pauli_4 = PauliString::from_text("ZYXIZI"); + let signs = bitvec![0, 1, 0, 1, 0, 0, 1, 1]; + let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3, pauli_4], signs); println!("{}", my_tableaus); - // test pauli polynomial + // // test pauli polynomial - let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - let pp = PauliPolynomial::from_hamiltonian(ham); - println!("{}", pp); + // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + // let pp = PauliPolynomial::from_hamiltonian(ham); + // println!("{}", pp); - // // visualize_pauli_exponential_simple(&pe); - let ham = vec![("IZZZ", 0.3)]; - let pp = PauliPolynomial::from_hamiltonian(ham); - let ct = CliffordTableau::new(4); - let pe = PauliExponential::new(VecDeque::from([pp]), ct); - println!("{}", pe); + // // // visualize_pauli_exponential_simple(&pe); + // let ham = vec![("IZZZ", 0.3)]; + // let pp = PauliPolynomial::from_hamiltonian(ham); + // let ct = CliffordTableau::new(4); + // let pe = PauliExponential::new(VecDeque::from([pp]), ct); + // println!("{}", pe); - // //visualize_pauli_exponential complex - let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + // // //visualize_pauli_exponential complex + // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); - let clifford_tableau = CliffordTableau::new(4); - let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); - println!("{}", complex_pe); + // let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); + // let clifford_tableau = CliffordTableau::new(4); + // let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); + // println!("{}", complex_pe); } diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 824280a1..cb2829e3 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -306,63 +306,114 @@ impl Mul for CliffordTableau { } impl fmt::Display for CliffordTableau { + // fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // write!(f, " ||")?; + // for i in 0..self.size() { + // write!(f, " X{} Z{}|", i + 1, i + 1)?; + // } + // writeln!(f)?; + // write!(f, "+/- ||")?; + // for (i, sign) in self.signs().iter().enumerate() { + // if *sign { + // write!(f, " - ")?; + // } else { + // write!(f, " + ")?; + // } + // if i % 2 != 0 { + // write!(f, "|")?; + // } + // } + // writeln!(f)?; + + // for (i, column) in self.pauli_columns.iter().enumerate() { + // write!(f, "QB{} ||", i)?; + // let mut out = String::new(); + // let mut letter_count = 0; + // for j in 0..column.len() { + // // let letter = column.pauli(j); + // match column.pauli(j) { + // PauliLetter::I => { + // out.push('I'); + // letter_count += 1; + // } + // PauliLetter::X => { + // out.push('X'); + // letter_count += 1; + // } + // PauliLetter::Z => { + // out.push('Z'); + // letter_count += 1; + // } + // PauliLetter::Y => { + // out.push('Y'); + // letter_count += 1; + // } + // } + // if letter_count % 2 == 1 { + // out.push(' '); + // } else { + // out.push_str(" |"); + // } + // out.push(' '); + // } + // out.push('\n'); + // write!(f, " {}", out)?; + // } + // writeln!(f) + // } + + // build a function that push the correct string character for each Pauli letter fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, " ||")?; - for i in 0..self.size() { - write!(f, " X{} Z{}|", i + 1, i + 1)?; - } - writeln!(f)?; - write!(f, "+/- ||")?; - for (i, sign) in self.signs().iter().enumerate() { - if *sign { - write!(f, " - ")?; + write!(f, " || Stabilizers | Destabilizers |\n")?; + let column0 = self.pauli_columns[0].len(); + for i in 0..column0 / 2 { + write!(f, "QB{} || ", i)?; + let sign = self.signs[i]; + if sign { + write!(f, "- ")?; } else { - write!(f, " + ")?; + write!(f, "+ ")?; } - if i % 2 != 0 { - write!(f, "|")?; + for column in self.pauli_columns.iter() { + let mut out = String::new(); + let ch = get_pauli_char(&column.pauli(i)); + out.push(ch); + write!(f, "{} ", out)?; } - } - writeln!(f)?; - - for (i, column) in self.pauli_columns.iter().enumerate() { - write!(f, "QB{} ||", i)?; - let mut out = String::new(); - let mut letter_count = 0; - for j in 0..column.len() { - // let letter = column.pauli(j); - match column.pauli(j) { - PauliLetter::I => { - out.push('I'); - letter_count += 1; - } - PauliLetter::X => { - out.push('X'); - letter_count += 1; - } - PauliLetter::Z => { - out.push('Z'); - letter_count += 1; - } - PauliLetter::Y => { - out.push('Y'); - letter_count += 1; - } - } - if letter_count % 2 == 1 { - out.push(' '); - } else { - out.push_str(" |"); - } - out.push(' '); + let space_left = 10 - 2 * self.pauli_columns.len(); + for _ in 0..space_left { + write!(f, " ")?; } - out.push('\n'); - write!(f, " {}", out)?; + write!(f, "| ")?; + let sign = self.signs[i + column0 / 2]; + if sign { + write!(f, "- ")?; + } else { + write!(f, "+ ")?; + } + for column in self.pauli_columns.iter() { + let mut out = String::new(); + let ch = get_pauli_char(&column.pauli(i + column0 / 2)); + out.push(ch); + write!(f, "{} ", out)?; + } + let space_left = 12 - 2 * self.pauli_columns.len(); + for _ in 0..space_left { + write!(f, " ")?; + } + writeln!(f, "|")?; } writeln!(f) } } - +pub fn get_pauli_char(letter: &PauliLetter) -> char { + match letter { + PauliLetter::I => 'I', + PauliLetter::X => 'X', + PauliLetter::Y => 'Y', + PauliLetter::Z => 'Z', + } +} #[cfg(test)] mod tests { use super::*; From b739ca7963954d460e09c161517d9fa0866c8bc5 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 2 Sep 2025 12:49:02 +0300 Subject: [PATCH 17/32] update test --- src/data_structures/clifford_tableau.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index cb2829e3..51e547e4 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -1290,7 +1290,7 @@ mod tests { let ct = setup_sample_ct(); assert_eq!( ct.to_string(), - " || X1 Z1| X2 Z2| X3 Z3|\n+/- || + - | + - | + + |\nQB0 || Z Y | I I | Z Z | \nQB1 || Z I | X X | I I | \nQB2 || Z Y | Y I | I Z | \n\n" + " || Stabilizers | Destabilizers |\nQB0 || + Z Z Z | - I X I |\nQB1 || - Y I Y | + Z I I |\nQB2 || + I X Y | + Z I Z |\n\n" ); } } From d0aa4604dcddd246818164ec23cd95b4ac7e7cf3 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 2 Sep 2025 14:24:11 +0300 Subject: [PATCH 18/32] change clifford tableau display trait to use string construction, for easier integration with pe display --- examples/print_data_structure.rs | 10 ++-- src/data_structures/clifford_tableau.rs | 61 ++++++++++++++++--------- src/data_structures/pauli_polynomial.rs | 4 +- 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index aff68df5..e9994b9b 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -20,17 +20,17 @@ fn main() { let pauli_3 = PauliString::from_text("ZYYIIZ"); // qubit 4x: ZYX // qubit 4z: IZI - let pauli_4 = PauliString::from_text("ZYXIZI"); + // let pauli_4 = PauliString::from_text("ZYXIZI"); let signs = bitvec![0, 1, 0, 1, 0, 0, 1, 1]; - let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3, pauli_4], signs); + let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); println!("{}", my_tableaus); // // test pauli polynomial - // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - // let pp = PauliPolynomial::from_hamiltonian(ham); - // println!("{}", pp); + let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; + let pp = PauliPolynomial::from_hamiltonian(ham); + println!("{}", pp); // // // visualize_pauli_exponential_simple(&pe); // let ham = vec![("IZZZ", 0.3)]; diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 51e547e4..13982c58 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -367,45 +367,63 @@ impl fmt::Display for CliffordTableau { write!(f, " || Stabilizers | Destabilizers |\n")?; let column0 = self.pauli_columns[0].len(); for i in 0..column0 / 2 { - write!(f, "QB{} || ", i)?; - let sign = self.signs[i]; - if sign { - write!(f, "- ")?; - } else { - write!(f, "+ ")?; - } + let mut out = String::new(); + //beginning of line string + out.push_str("QB"); + out.push_str(&i.to_string()); + out.push_str(" || "); + + //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 mut out = String::new(); let ch = get_pauli_char(&column.pauli(i)); out.push(ch); - write!(f, "{} ", out)?; + out.push(' '); } + + //add space due to the length of "stabilizers" string let space_left = 10 - 2 * self.pauli_columns.len(); for _ in 0..space_left { - write!(f, " ")?; - } - write!(f, "| ")?; - let sign = self.signs[i + column0 / 2]; - if sign { - write!(f, "- ")?; - } else { - write!(f, "+ ")?; + out.push(' '); } + + //add separator between stabilizers and destabilizers + out.push_str("| "); + + //add sign for destabilizers + out.push(get_pauli_sign(self.signs[i + column0 / 2])); + out.push(' '); + + // add destabilizers pauli for column in self.pauli_columns.iter() { - let mut out = String::new(); let ch = get_pauli_char(&column.pauli(i + column0 / 2)); out.push(ch); - write!(f, "{} ", out)?; + out.push(' '); } + + //add space due to the length of "destabilizers" string let space_left = 12 - 2 * self.pauli_columns.len(); for _ in 0..space_left { - write!(f, " ")?; + out.push(' '); } - writeln!(f, "|")?; + out.push('|'); + writeln!(f, "{}", out)?; } writeln!(f) } } + +pub fn get_pauli_sign(sign: bool) -> char { + if sign { + '-' + } else { + '+' + } +} + pub fn get_pauli_char(letter: &PauliLetter) -> char { match letter { PauliLetter::I => 'I', @@ -414,6 +432,7 @@ pub fn get_pauli_char(letter: &PauliLetter) -> char { PauliLetter::Z => 'Z', } } + #[cfg(test)] mod tests { use super::*; diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 57a80e16..594326a8 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -177,10 +177,10 @@ impl fmt::Display for PauliPolynomial { .iter() .map(|x| format!("{:.3}", x)) //force 3 decimal place for formatting .join(" | "); - writeln!(f, "Angles | {} |", string_angles)?; + writeln!(f, "Angles || {} |", string_angles)?; let chains = self.chains(); for (i, pauli) in chains.iter().enumerate() { - write!(f, "Qubit {}|", i)?; + write!(f, "QB{} ||", i)?; let chain_str = pauli.to_string(); let mut out = String::new(); for ch in chain_str.chars() { From ff982f1c94475114be320050334e741917fe35c6 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 2 Sep 2025 14:30:15 +0300 Subject: [PATCH 19/32] update test --- src/data_structures/clifford_tableau.rs | 58 +------------------------ src/data_structures/pauli_polynomial.rs | 2 +- 2 files changed, 2 insertions(+), 58 deletions(-) diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 13982c58..dbac91e3 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -306,64 +306,8 @@ impl Mul for CliffordTableau { } impl fmt::Display for CliffordTableau { - // fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // write!(f, " ||")?; - // for i in 0..self.size() { - // write!(f, " X{} Z{}|", i + 1, i + 1)?; - // } - // writeln!(f)?; - // write!(f, "+/- ||")?; - // for (i, sign) in self.signs().iter().enumerate() { - // if *sign { - // write!(f, " - ")?; - // } else { - // write!(f, " + ")?; - // } - // if i % 2 != 0 { - // write!(f, "|")?; - // } - // } - // writeln!(f)?; - - // for (i, column) in self.pauli_columns.iter().enumerate() { - // write!(f, "QB{} ||", i)?; - // let mut out = String::new(); - // let mut letter_count = 0; - // for j in 0..column.len() { - // // let letter = column.pauli(j); - // match column.pauli(j) { - // PauliLetter::I => { - // out.push('I'); - // letter_count += 1; - // } - // PauliLetter::X => { - // out.push('X'); - // letter_count += 1; - // } - // PauliLetter::Z => { - // out.push('Z'); - // letter_count += 1; - // } - // PauliLetter::Y => { - // out.push('Y'); - // letter_count += 1; - // } - // } - // if letter_count % 2 == 1 { - // out.push(' '); - // } else { - // out.push_str(" |"); - // } - // out.push(' '); - // } - // out.push('\n'); - // write!(f, " {}", out)?; - // } - // writeln!(f) - // } - - // build a function that push the correct string character for each Pauli letter fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + //first line write!(f, " || Stabilizers | Destabilizers |\n")?; let column0 = self.pauli_columns[0].len(); for i in 0..column0 / 2 { diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 594326a8..6c5dc22a 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -617,7 +617,7 @@ mod tests { let pp = setup_sample_pp(); assert_eq!( pp.to_string(), - "Angles | 0.300 | 0.700 | 0.120 |\nQubit 0| I | X | Y |\nQubit 1| Z | Y | X |\nQubit 2| Y | I | X |\n\n" + "Angles || 0.300 | 0.700 | 0.120 |\nQB0 || I | X | Y |\nQB1 || Z | Y | X |\nQB2 || Y | I | X |\n\n" ); } } From 2f9c90a0b068b6875cf6810e2528b2f584a5c727 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 2 Sep 2025 17:11:37 +0300 Subject: [PATCH 20/32] fix tableaux because French --- examples/print_data_structure.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index e9994b9b..9b75d494 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -22,9 +22,9 @@ fn main() { // qubit 4z: IZI // let pauli_4 = PauliString::from_text("ZYXIZI"); let signs = bitvec![0, 1, 0, 1, 0, 0, 1, 1]; - let my_tableaus = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); + let my_tableaux = CliffordTableau::from_parts(vec![pauli_1, pauli_2, pauli_3], signs); - println!("{}", my_tableaus); + println!("{}", my_tableaux); // // test pauli polynomial From 705cf68ceab587d8c831cfd49d4db801b549ec3e Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 4 Sep 2025 11:27:25 +0300 Subject: [PATCH 21/32] added new display for Pauli Exponential --- examples/print_data_structure.rs | 10 +-- src/data_structures/clifford_tableau.rs | 81 ++++++++++++++----------- src/data_structures/pauli_polynomial.rs | 53 +++++++++++----- src/ir/pauli_exponential.rs | 18 ++++-- tests/clifford_tableau.rs | 3 +- 5 files changed, 101 insertions(+), 64 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index 9b75d494..e9902d32 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -33,11 +33,11 @@ fn main() { println!("{}", pp); // // // visualize_pauli_exponential_simple(&pe); - // let ham = vec![("IZZZ", 0.3)]; - // let pp = PauliPolynomial::from_hamiltonian(ham); - // let ct = CliffordTableau::new(4); - // let pe = PauliExponential::new(VecDeque::from([pp]), ct); - // println!("{}", pe); + let ham = vec![("IZZZ", 0.3)]; + let pp = PauliPolynomial::from_hamiltonian(ham); + let ct = CliffordTableau::new(4); + let pe = PauliExponential::new(VecDeque::from([pp]), ct); + println!("{}", pe); // // //visualize_pauli_exponential complex // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index dbac91e3..0c436ca7 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -65,6 +65,49 @@ impl CliffordTableau { rhs.prepend(self) } + pub(crate) fn get_line_string(&self, i: usize) -> String { + 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(' '); + } + + //add space due to the length of "stabilizers" string + let space_left = 10 - 2 * self.pauli_columns.len(); + 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 + let space_left = 12 - 2 * self.pauli_columns.len(); + for _ in 0..space_left { + out.push(' '); + } + out.push('|'); + 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(); @@ -317,43 +360,7 @@ impl fmt::Display for CliffordTableau { out.push_str(&i.to_string()); out.push_str(" || "); - //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(' '); - } - - //add space due to the length of "stabilizers" string - let space_left = 10 - 2 * self.pauli_columns.len(); - 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 + column0 / 2])); - out.push(' '); - - // add destabilizers pauli - for column in self.pauli_columns.iter() { - let ch = get_pauli_char(&column.pauli(i + column0 / 2)); - out.push(ch); - out.push(' '); - } - - //add space due to the length of "destabilizers" string - let space_left = 12 - 2 * self.pauli_columns.len(); - for _ in 0..space_left { - out.push(' '); - } - out.push('|'); + out.push_str(&self.get_line_string(i)); writeln!(f, "{}", out)?; } writeln!(f) diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index 6c5dc22a..a2d111c5 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -69,6 +69,34 @@ impl PauliPolynomial { pub fn angle(&self, i: usize) -> Angle { self.angles.read().unwrap()[i] } + + pub fn get_line_string(&self, i: usize) -> String { + let mut out = String::new(); + //beginning of line string + out.push_str("QB"); + out.push_str(&i.to_string()); + out.push_str(" || "); + 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(); + //beginning of line string + out.push_str("Angles ||"); + let angles = self.angles.read().unwrap(); + for angle in angles.iter() { + out.push_str(&format!(" {:.3}", angle)); //force 3 decimal place for formatting + out.push_str(" |"); + } + out + } } impl PropagateClifford for PauliPolynomial { @@ -172,24 +200,17 @@ impl MaskedPropagateClifford for PauliPolynomial { impl fmt::Display for PauliPolynomial { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let angles = self.angles.read().unwrap(); - let string_angles = angles - .iter() - .map(|x| format!("{:.3}", x)) //force 3 decimal place for formatting - .join(" | "); - writeln!(f, "Angles || {} |", string_angles)?; + // write first line + let mut out = String::new(); + out.push_str(&self.get_first_line_string()); + writeln!(f, "{}", out)?; + + // write subsequent lines let chains = self.chains(); - for (i, pauli) in chains.iter().enumerate() { - write!(f, "QB{} ||", i)?; - let chain_str = pauli.to_string(); + for (i, _) in chains.iter().enumerate() { let mut out = String::new(); - for ch in chain_str.chars() { - out.push(ch); - if !ch.is_whitespace() { - out.push_str(" |"); - } - } - writeln!(f, " {}", out)?; + out.push_str(&self.get_line_string(i)); + writeln!(f, "{}", out)?; } writeln!(f) } diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index ddc314af..a1d8296c 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -32,11 +32,19 @@ impl PauliExponential { impl fmt::Display for PauliExponential { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - writeln!(f, "Clifford Tableau: \n{}", self.clifford_tableau)?; - writeln!(f, "Pauli Polynomials:")?; - for (i, pp) in self.pauli_polynomials.iter().enumerate() { - writeln!(f, "Pauli {} ", i)?; - writeln!(f, "{}", pp)?; + let ct = &self.clifford_tableau; + let pp = &self.pauli_polynomials[0]; + let mut out = String::new(); + out.push_str(pp.get_first_line_string().as_str()); + out.push_str("| Stabilizers | Destabilizers |"); + out.push_str("\n"); + write!(f, "{}", out)?; + for i in 0..ct.column(0).len() / 2 { + let mut out = String::new(); + out.push_str(pp.get_line_string(i).as_str()); + out.push_str("| "); + out.push_str(ct.get_line_string(i).as_str()); + writeln!(f, "{}", out)?; } writeln!(f) } diff --git a/tests/clifford_tableau.rs b/tests/clifford_tableau.rs index 9ef7a123..ee2b667b 100644 --- a/tests/clifford_tableau.rs +++ b/tests/clifford_tableau.rs @@ -18,7 +18,8 @@ fn setup_sample_ct() -> CliffordTableau { // qubit 2z: XII let pauli_2 = PauliString::from_text("ZIXXII"); - // qubit 3x: ZYY + // qubit 3x: ZY + // qubit 3z: IIZ let pauli_3 = PauliString::from_text("ZYYIIZ"); From f7b8a55a596960e7a9106d65b8d5a66ffdb0b074 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Wed, 10 Sep 2025 12:28:51 +0300 Subject: [PATCH 22/32] support multi pauli polynomials printing for pauli exponential --- examples/print_data_structure.rs | 6 ++++-- src/ir/pauli_exponential.rs | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index e9902d32..3e1f4865 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -34,9 +34,11 @@ fn main() { // // // visualize_pauli_exponential_simple(&pe); let ham = vec![("IZZZ", 0.3)]; - let pp = PauliPolynomial::from_hamiltonian(ham); + let pp1 = PauliPolynomial::from_hamiltonian(ham); let ct = CliffordTableau::new(4); - let pe = PauliExponential::new(VecDeque::from([pp]), ct); + let ham2 = vec![("XIII", 0.7)]; + let pp2 = PauliPolynomial::from_hamiltonian(ham2); + let pe = PauliExponential::new(VecDeque::from([pp1, pp, pp2]), ct); println!("{}", pe); // // //visualize_pauli_exponential complex diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index a1d8296c..ce920890 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -32,20 +32,26 @@ impl PauliExponential { impl fmt::Display for PauliExponential { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut out: String = String::new(); let ct = &self.clifford_tableau; - let pp = &self.pauli_polynomials[0]; - let mut out = String::new(); - out.push_str(pp.get_first_line_string().as_str()); + for pp in &self.pauli_polynomials { + out.push_str(pp.get_first_line_string().as_str()); + } + // out.push_str(pp.get_first_line_string().as_str()); out.push_str("| Stabilizers | Destabilizers |"); out.push_str("\n"); - write!(f, "{}", out)?; + for i in 0..ct.column(0).len() / 2 { - let mut out = String::new(); - out.push_str(pp.get_line_string(i).as_str()); + // let mut out = String::new(); + for pp in &self.pauli_polynomials { + out.push_str(pp.get_line_string(i).as_str()); + } + // out.push_str(pp.get_line_string(i).as_str()); out.push_str("| "); out.push_str(ct.get_line_string(i).as_str()); - writeln!(f, "{}", out)?; + out.push_str("\n"); } + write!(f, "{}", out)?; writeln!(f) } } From 367d1855fe20c263a1f6af70bbe9d77e08d7e717 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Wed, 10 Sep 2025 12:43:37 +0300 Subject: [PATCH 23/32] fix pauli exponential display to not show multiple 'QB' column --- src/data_structures/pauli_polynomial.rs | 8 ++++---- src/ir/pauli_exponential.rs | 10 ++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index a2d111c5..e934dcf6 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -73,9 +73,6 @@ impl PauliPolynomial { pub fn get_line_string(&self, i: usize) -> String { let mut out = String::new(); //beginning of line string - out.push_str("QB"); - out.push_str(&i.to_string()); - out.push_str(" || "); let chain_str = self.chains[i].to_string(); for ch in chain_str.chars() { out.push(ch); @@ -89,7 +86,6 @@ impl PauliPolynomial { pub fn get_first_line_string(&self) -> String { let mut out = String::new(); //beginning of line string - out.push_str("Angles ||"); let angles = self.angles.read().unwrap(); for angle in angles.iter() { out.push_str(&format!(" {:.3}", angle)); //force 3 decimal place for formatting @@ -202,6 +198,7 @@ impl fmt::Display for PauliPolynomial { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // write first line let mut out = String::new(); + out.push_str("Angles ||"); out.push_str(&self.get_first_line_string()); writeln!(f, "{}", out)?; @@ -209,6 +206,9 @@ impl fmt::Display for PauliPolynomial { 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)?; } diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index ce920890..ba2cd70e 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -34,20 +34,26 @@ impl fmt::Display for PauliExponential { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut out: String = String::new(); let ct = &self.clifford_tableau; + out.push_str("Angles ||"); for pp in &self.pauli_polynomials { out.push_str(pp.get_first_line_string().as_str()); + out.push('|'); } // out.push_str(pp.get_first_line_string().as_str()); - out.push_str("| Stabilizers | Destabilizers |"); + out.push_str(" Stabilizers | Destabilizers |"); out.push_str("\n"); for i in 0..ct.column(0).len() / 2 { // let mut out = String::new(); + out.push_str("QB"); + out.push_str(&i.to_string()); + out.push_str(" || "); for pp in &self.pauli_polynomials { out.push_str(pp.get_line_string(i).as_str()); + out.push_str("| "); } // out.push_str(pp.get_line_string(i).as_str()); - out.push_str("| "); + // out.push_str(" "); out.push_str(ct.get_line_string(i).as_str()); out.push_str("\n"); } From 832716f3b871d2e5ceb061cba24c12f3235e6e92 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Wed, 10 Sep 2025 15:45:57 +0300 Subject: [PATCH 24/32] add logic to correctly format clifford tableaux for big case. Also clean up comment and add some more tests --- examples/print_data_structure.rs | 27 ++++++-------- src/data_structures/clifford_tableau.rs | 47 ++++++++++++++++++------- src/data_structures/pauli_polynomial.rs | 6 ++-- src/ir/pauli_exponential.rs | 8 +---- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index 3e1f4865..fa502740 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -20,32 +20,27 @@ fn main() { let pauli_3 = PauliString::from_text("ZYYIIZ"); // qubit 4x: ZYX // qubit 4z: IZI - // let pauli_4 = PauliString::from_text("ZYXIZI"); 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); - - // // test pauli polynomial + let big_tableaux = CliffordTableau::new(10); + 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); - // // // visualize_pauli_exponential_simple(&pe); - let ham = vec![("IZZZ", 0.3)]; - let pp1 = PauliPolynomial::from_hamiltonian(ham); + 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([pp1, pp, pp2]), ct); - println!("{}", pe); + let pe = PauliExponential::new(VecDeque::from([pp, pp1, pp2]), ct); - // // //visualize_pauli_exponential complex - // let ham = vec![("IXYZ", 0.3), ("XXII", 0.7), ("YYII", 0.12)]; - - // let pauli_polynomial = PauliPolynomial::from_hamiltonian(ham); - // let clifford_tableau = CliffordTableau::new(4); - // let complex_pe = PauliExponential::new(VecDeque::from([pauli_polynomial]), clifford_tableau); - // println!("{}", complex_pe); + println!("Test pauli exponential"); + println!("{}", pe); } diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 0c436ca7..51fc7789 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -66,6 +66,7 @@ impl CliffordTableau { } 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 @@ -79,10 +80,11 @@ impl CliffordTableau { out.push(' '); } - //add space due to the length of "stabilizers" string - let space_left = 10 - 2 * self.pauli_columns.len(); - for _ in 0..space_left { - out.push(' '); + if number_of_column <= 5 { + let space_left = 10 - 2 * number_of_column; + for _ in 0..space_left { + out.push(' '); + } } //add separator between stabilizers and destabilizers @@ -100,14 +102,34 @@ impl CliffordTableau { } //add space due to the length of "destabilizers" string - let space_left = 12 - 2 * self.pauli_columns.len(); - for _ in 0..space_left { - out.push(' '); + if number_of_column <= 6 { + let space_left = 12 - 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(" Stabilizers | Destabilizers |\n"); + } else { + out.push_str(" Stabilizers"); + for _ in 0..number_of_column - 5 { + out.push_str(" "); + } + out.push_str(" | Destabilizers"); + for _ in 0..number_of_column - 6 { + 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(); @@ -350,8 +372,10 @@ impl Mul for CliffordTableau { impl fmt::Display for CliffordTableau { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - //first line - write!(f, " || Stabilizers | Destabilizers |\n")?; + let mut out: String = String::new(); + 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(); @@ -359,7 +383,6 @@ impl fmt::Display for CliffordTableau { out.push_str("QB"); out.push_str(&i.to_string()); out.push_str(" || "); - out.push_str(&self.get_line_string(i)); writeln!(f, "{}", out)?; } @@ -375,7 +398,7 @@ pub fn get_pauli_sign(sign: bool) -> char { } } -pub fn get_pauli_char(letter: &PauliLetter) -> char { +pub(crate) fn get_pauli_char(letter: &PauliLetter) -> char { match letter { PauliLetter::I => 'I', PauliLetter::X => 'X', diff --git a/src/data_structures/pauli_polynomial.rs b/src/data_structures/pauli_polynomial.rs index e934dcf6..7cd54740 100644 --- a/src/data_structures/pauli_polynomial.rs +++ b/src/data_structures/pauli_polynomial.rs @@ -72,7 +72,6 @@ impl PauliPolynomial { pub fn get_line_string(&self, i: usize) -> String { let mut out = String::new(); - //beginning of line string let chain_str = self.chains[i].to_string(); for ch in chain_str.chars() { out.push(ch); @@ -85,7 +84,6 @@ impl PauliPolynomial { pub fn get_first_line_string(&self) -> String { let mut out = String::new(); - //beginning of line string let angles = self.angles.read().unwrap(); for angle in angles.iter() { out.push_str(&format!(" {:.3}", angle)); //force 3 decimal place for formatting @@ -198,7 +196,7 @@ impl fmt::Display for PauliPolynomial { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // write first line let mut out = String::new(); - out.push_str("Angles ||"); + 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)?; @@ -206,7 +204,7 @@ impl fmt::Display for PauliPolynomial { let chains = self.chains(); for (i, _) in chains.iter().enumerate() { let mut out = String::new(); - out.push_str("QB"); + out.push_str("QB"); //same here out.push_str(&i.to_string()); out.push_str(" || "); out.push_str(&self.get_line_string(i)); diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index ba2cd70e..78c897b6 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -39,12 +39,8 @@ impl fmt::Display for PauliExponential { out.push_str(pp.get_first_line_string().as_str()); out.push('|'); } - // out.push_str(pp.get_first_line_string().as_str()); - out.push_str(" Stabilizers | Destabilizers |"); - out.push_str("\n"); - + out.push_str(&ct.get_first_line_string()); for i in 0..ct.column(0).len() / 2 { - // let mut out = String::new(); out.push_str("QB"); out.push_str(&i.to_string()); out.push_str(" || "); @@ -52,8 +48,6 @@ impl fmt::Display for PauliExponential { out.push_str(pp.get_line_string(i).as_str()); out.push_str("| "); } - // out.push_str(pp.get_line_string(i).as_str()); - // out.push_str(" "); out.push_str(ct.get_line_string(i).as_str()); out.push_str("\n"); } From e5694c44f69ef8ed47170ab223155cb8a31b0173 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 11 Sep 2025 07:31:05 +0300 Subject: [PATCH 25/32] support print alignment of up to 99 qubits --- examples/print_data_structure.rs | 2 +- src/data_structures/clifford_tableau.rs | 5 ++++- src/ir/pauli_exponential.rs | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index fa502740..e313b58d 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -24,7 +24,7 @@ fn main() { 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(10); + let big_tableaux = CliffordTableau::new(20); println!("Test clifford tableaux big"); println!("{}", big_tableaux); diff --git a/src/data_structures/clifford_tableau.rs b/src/data_structures/clifford_tableau.rs index 51fc7789..64910bed 100644 --- a/src/data_structures/clifford_tableau.rs +++ b/src/data_structures/clifford_tableau.rs @@ -382,7 +382,10 @@ impl fmt::Display for CliffordTableau { //beginning of line string out.push_str("QB"); out.push_str(&i.to_string()); - out.push_str(" || "); + if i < 10 { + out.push(' '); + } + out.push_str("|| "); out.push_str(&self.get_line_string(i)); writeln!(f, "{}", out)?; } diff --git a/src/ir/pauli_exponential.rs b/src/ir/pauli_exponential.rs index 78c897b6..3259ea3f 100644 --- a/src/ir/pauli_exponential.rs +++ b/src/ir/pauli_exponential.rs @@ -43,7 +43,10 @@ impl fmt::Display for PauliExponential { for i in 0..ct.column(0).len() / 2 { out.push_str("QB"); out.push_str(&i.to_string()); - out.push_str(" || "); + if i < 10 { + out.push(' '); + } + out.push_str(" || "); for pp in &self.pauli_polynomials { out.push_str(pp.get_line_string(i).as_str()); out.push_str("| "); From 695551f1ff7b4509e19d3380b263afb20dfae884 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Tue, 21 Oct 2025 11:12:59 +0300 Subject: [PATCH 26/32] test print empty data structure --- examples/print_data_structure.rs | 44 ++++++++++++++++++++++++++++++++ synpy/src/tableau.rs | 3 +++ 2 files changed, 47 insertions(+) diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs index e313b58d..17d43a69 100644 --- a/examples/print_data_structure.rs +++ b/examples/print_data_structure.rs @@ -43,4 +43,48 @@ fn main() { 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"); + } +} + +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::from_hamiltonian(vec![]); + println!("Empty Pauli Polynomial:"); + println!("{}", empty_pauli_polynomial); +} + +fn test_empty_pauli_exponential() { + let empty_ct = CliffordTableau::new(0); + let empty_pp = PauliPolynomial::from_hamiltonian(vec![]); + let empty_pe = PauliExponential::new(VecDeque::from([empty_pp]), empty_ct); + println!("Empty Pauli Exponential:"); + print!("{}", empty_pe); } diff --git a/synpy/src/tableau.rs b/synpy/src/tableau.rs index e56f2e86..469cc3ed 100644 --- a/synpy/src/tableau.rs +++ b/synpy/src/tableau.rs @@ -24,6 +24,9 @@ impl PyCliffordTableau { tableau: CliffordTableau::new(n), } } + fn __str__(&self) -> PyResult { + Ok(self.tableau.to_string()) + } #[staticmethod] pub fn from_parts(pauli_strings: Vec, signs: Vec) -> Self { From 1f0a1e6f81711b91a28a6ff6cfd1044eab1e44e3 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 23 Oct 2025 11:04:38 +0300 Subject: [PATCH 27/32] swap Stabilizer/Destabilizer --- examples/print_data_structure.rs | 90 ------------------- synir/src/data_structures/clifford_tableau.rs | 14 +-- 2 files changed, 7 insertions(+), 97 deletions(-) delete mode 100644 examples/print_data_structure.rs diff --git a/examples/print_data_structure.rs b/examples/print_data_structure.rs deleted file mode 100644 index 17d43a69..00000000 --- a/examples/print_data_structure.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::collections::VecDeque; - -use bitvec::bitvec; -use bitvec::prelude::Lsb0; -use syn::data_structures::{CliffordTableau, PauliPolynomial, PauliString}; -use syn::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"); - } -} - -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::from_hamiltonian(vec![]); - println!("Empty Pauli Polynomial:"); - println!("{}", empty_pauli_polynomial); -} - -fn test_empty_pauli_exponential() { - let empty_ct = CliffordTableau::new(0); - let empty_pp = PauliPolynomial::from_hamiltonian(vec![]); - let empty_pe = PauliExponential::new(VecDeque::from([empty_pp]), empty_ct); - println!("Empty Pauli Exponential:"); - print!("{}", empty_pe); -} diff --git a/synir/src/data_structures/clifford_tableau.rs b/synir/src/data_structures/clifford_tableau.rs index 2ddc2894..6e1758bb 100644 --- a/synir/src/data_structures/clifford_tableau.rs +++ b/synir/src/data_structures/clifford_tableau.rs @@ -81,7 +81,7 @@ impl CliffordTableau { } if number_of_column <= 5 { - let space_left = 10 - 2 * number_of_column; + let space_left = 12 - 2 * number_of_column; for _ in 0..space_left { out.push(' '); } @@ -103,7 +103,7 @@ impl CliffordTableau { //add space due to the length of "destabilizers" string if number_of_column <= 6 { - let space_left = 12 - 2 * self.pauli_columns.len(); + let space_left = 10 - 2 * self.pauli_columns.len(); for _ in 0..space_left { out.push(' '); } @@ -116,14 +116,14 @@ impl CliffordTableau { let number_of_column = self.pauli_columns.len(); let mut out = String::new(); if number_of_column <= 5 { - out.push_str(" Stabilizers | Destabilizers |\n"); + out.push_str(" Destabilizers | Stabilizers |\n"); } else { - out.push_str(" Stabilizers"); - for _ in 0..number_of_column - 5 { + out.push_str(" Destabilizers"); + for _ in 0..number_of_column - 6 { out.push_str(" "); } - out.push_str(" | Destabilizers"); - for _ in 0..number_of_column - 6 { + out.push_str(" | Stabilizers"); + for _ in 0..number_of_column - 5 { out.push_str(" "); } out.push_str(" |\n"); From f9502fe5586d3a740331be22484d6e47a9067234 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 23 Oct 2025 17:38:16 +0300 Subject: [PATCH 28/32] add print empty for clifford tableau and pauli polynomial --- synir/examples/print_data_structure.rs | 2 +- synir/src/data_structures/clifford_tableau.rs | 36 ++++++++------ synir/src/data_structures/pauli_polynomial.rs | 47 +++++++++++++------ 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/synir/examples/print_data_structure.rs b/synir/examples/print_data_structure.rs index 7e6f0b70..f8e34164 100644 --- a/synir/examples/print_data_structure.rs +++ b/synir/examples/print_data_structure.rs @@ -76,7 +76,7 @@ fn test_empty_clifford_tableau() { } fn test_empty_pauli_polynomial() { - let empty_pauli_polynomial = PauliPolynomial::from_hamiltonian(vec![]); + let empty_pauli_polynomial = PauliPolynomial::empty(5); println!("Empty Pauli Polynomial:"); println!("{}", empty_pauli_polynomial); } diff --git a/synir/src/data_structures/clifford_tableau.rs b/synir/src/data_structures/clifford_tableau.rs index 6e1758bb..7e388412 100644 --- a/synir/src/data_structures/clifford_tableau.rs +++ b/synir/src/data_structures/clifford_tableau.rs @@ -371,23 +371,29 @@ impl Mul for CliffordTableau { impl fmt::Display for CliffordTableau { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut out: String = String::new(); - 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)); + 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)?; + } + writeln!(f) } - writeln!(f) } } diff --git a/synir/src/data_structures/pauli_polynomial.rs b/synir/src/data_structures/pauli_polynomial.rs index 5c3d4a90..398b3bfe 100644 --- a/synir/src/data_structures/pauli_polynomial.rs +++ b/synir/src/data_structures/pauli_polynomial.rs @@ -80,13 +80,20 @@ impl PauliPolynomial { pub fn get_first_line_string(&self) -> String { let mut out = String::new(); - // let angles = self.angles.read().unwrap(); 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 { @@ -188,22 +195,34 @@ impl MaskedPropagateClifford for PauliPolynomial { impl fmt::Display for PauliPolynomial { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // write first line let mut out = String::new(); - 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"); //same here - out.push_str(&i.to_string()); - out.push_str(" || "); - out.push_str(&self.get_line_string(i)); + if self.angles.is_empty() { + out.push_str("Angles || None|\n"); + for i in 0..self.size() { + out.push_str("QB"); + out.push_str(&i.to_string()); + out.push_str(" || "); + 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) } } From 5a2fa618e42a460fa292b87fd683a2517be7f3e4 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Thu, 23 Oct 2025 17:45:21 +0300 Subject: [PATCH 29/32] fix test to pass build --- synir/src/data_structures/clifford_tableau.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synir/src/data_structures/clifford_tableau.rs b/synir/src/data_structures/clifford_tableau.rs index 7e388412..bf47cb70 100644 --- a/synir/src/data_structures/clifford_tableau.rs +++ b/synir/src/data_structures/clifford_tableau.rs @@ -1290,7 +1290,7 @@ mod tests { let ct = setup_sample_ct(); assert_eq!( ct.to_string(), - " || Stabilizers | Destabilizers |\nQB0 || + Z Z Z | - I X I |\nQB1 || - Y I Y | + Z I I |\nQB2 || + I X Y | + Z I Z |\n\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" ); } } From 26f053cbee56d24f345a7e66a5ade9b8215ce3b1 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 24 Oct 2025 09:36:23 +0300 Subject: [PATCH 30/32] test display fix --- synir/src/data_structures/clifford_tableau.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synir/src/data_structures/clifford_tableau.rs b/synir/src/data_structures/clifford_tableau.rs index bf47cb70..ea385ba0 100644 --- a/synir/src/data_structures/clifford_tableau.rs +++ b/synir/src/data_structures/clifford_tableau.rs @@ -1290,7 +1290,7 @@ mod tests { let ct = setup_sample_ct(); assert_eq!( ct.to_string(), - " || 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" + " || 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" ); } } From 201ae27226c0eb00f73f652355dcbf4b3bcf7804 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 24 Oct 2025 10:07:36 +0300 Subject: [PATCH 31/32] added printing empty logic for all data structures --- synir/examples/print_data_structure.rs | 21 +++++++++-- synir/src/data_structures/pauli_polynomial.rs | 35 +++++++++++++------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/synir/examples/print_data_structure.rs b/synir/examples/print_data_structure.rs index f8e34164..c668bdca 100644 --- a/synir/examples/print_data_structure.rs +++ b/synir/examples/print_data_structure.rs @@ -67,6 +67,13 @@ fn main() { 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() { @@ -82,9 +89,19 @@ fn test_empty_pauli_polynomial() { } fn test_empty_pauli_exponential() { - let empty_ct = CliffordTableau::new(0); - let empty_pp = PauliPolynomial::from_hamiltonian(vec![]); + let empty_ct = CliffordTableau::new(5); + let empty_pp = PauliPolynomial::empty(5); let empty_pe = PauliExponential::new(VecDeque::from([empty_pp]), 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); +} diff --git a/synir/src/data_structures/pauli_polynomial.rs b/synir/src/data_structures/pauli_polynomial.rs index 398b3bfe..9bc8b909 100644 --- a/synir/src/data_structures/pauli_polynomial.rs +++ b/synir/src/data_structures/pauli_polynomial.rs @@ -68,11 +68,16 @@ impl PauliPolynomial { pub fn get_line_string(&self, i: usize) -> String { let mut out = String::new(); - let chain_str = self.chains[i].to_string(); - for ch in chain_str.chars() { - out.push(ch); - if !ch.is_whitespace() { - out.push_str(" |"); + 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 @@ -80,9 +85,13 @@ impl PauliPolynomial { pub fn get_first_line_string(&self) -> String { let mut out = String::new(); - for angle in self.angles.iter() { - out.push_str(&format!(" {:.3}", angle)); //force 3 decimal place for formatting - out.push_str(" |"); + 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 } @@ -196,13 +205,18 @@ impl MaskedPropagateClifford for PauliPolynomial { 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 || None|\n"); + 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("_ |\n"); + out.push_str(&self.get_line_string(i)); + out.push_str("\n"); + // out.push_str("_ |\n"); } writeln!(f, "{}", out)?; } else { @@ -222,7 +236,6 @@ impl fmt::Display for PauliPolynomial { writeln!(f, "{}", out)?; } } - writeln!(f) } } From 1bcbf4655205e03b606e7f6aa31b33cba5baffa8 Mon Sep 17 00:00:00 2001 From: Tung Bui Date: Fri, 24 Oct 2025 10:46:32 +0300 Subject: [PATCH 32/32] add some edge case for printing empty exponential --- synir/examples/print_data_structure.rs | 2 +- synir/src/ir/pauli_exponential.rs | 50 +++++++++++++++++--------- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/synir/examples/print_data_structure.rs b/synir/examples/print_data_structure.rs index c668bdca..c003a15a 100644 --- a/synir/examples/print_data_structure.rs +++ b/synir/examples/print_data_structure.rs @@ -91,7 +91,7 @@ fn test_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_pp]), empty_ct); + let empty_pe = PauliExponential::new(VecDeque::from([]), empty_ct); println!("Empty Pauli Exponential:"); print!("{}", empty_pe); } diff --git a/synir/src/ir/pauli_exponential.rs b/synir/src/ir/pauli_exponential.rs index 3259ea3f..c9702a40 100644 --- a/synir/src/ir/pauli_exponential.rs +++ b/synir/src/ir/pauli_exponential.rs @@ -33,27 +33,43 @@ impl PauliExponential { impl fmt::Display for PauliExponential { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut out: String = String::new(); - let ct = &self.clifford_tableau; - out.push_str("Angles ||"); - for pp in &self.pauli_polynomials { - out.push_str(pp.get_first_line_string().as_str()); - out.push('|'); - } - out.push_str(&ct.get_first_line_string()); - for i in 0..ct.column(0).len() / 2 { - out.push_str("QB"); - out.push_str(&i.to_string()); - if i < 10 { - out.push(' '); + if self.pauli_polynomials.is_empty() { + out.push_str("Angles || No poly ||"); + out.push_str(&self.clifford_tableau.get_first_line_string()); + for i in 0..&self.clifford_tableau.column(0).len() / 2 { + out.push_str("QB"); + out.push_str(&i.to_string()); + if i < 10 { + out.push(' '); + } + out.push_str(" || _______ || "); + out.push_str(&self.clifford_tableau.get_line_string(i).as_str()); + out.push_str("\n"); } - out.push_str(" || "); + } else { + out.push_str("Angles ||"); for pp in &self.pauli_polynomials { - out.push_str(pp.get_line_string(i).as_str()); - out.push_str("| "); + out.push_str(pp.get_first_line_string().as_str()); + out.push('|'); + } + out.push_str(&self.clifford_tableau.get_first_line_string()); + + for i in 0..&self.clifford_tableau.column(0).len() / 2 { + out.push_str("QB"); + out.push_str(&i.to_string()); + if i < 10 { + out.push(' '); + } + out.push_str(" || "); + for pp in &self.pauli_polynomials { + out.push_str(pp.get_line_string(i).as_str()); + out.push_str("| "); + } + out.push_str(&self.clifford_tableau.get_line_string(i).as_str()); + out.push_str("\n"); } - out.push_str(ct.get_line_string(i).as_str()); - out.push_str("\n"); } + write!(f, "{}", out)?; writeln!(f) }