ppvm_pauli_word/pattern/
parse.rs1use anyhow::Result;
5use std::collections::BTreeSet;
6
7use super::data::{Decorated, NotIdentity, OpPattern, PauliPattern};
8
9impl PauliPattern {
10 pub fn parse(input: impl AsRef<str>) -> Result<Self> {
33 let mut patterns = Vec::new();
34 let mut chars = input.as_ref().trim().chars().peekable();
35 while let Some(c) = chars.next() {
36 let op = match c {
37 '[' => {
38 let mut alter = BTreeSet::new();
39 while let Some(ch) = chars.peek() {
40 let op = match ch {
41 ']' => {
42 chars.next(); break;
44 }
45 'X' => {
46 chars.next();
47 NotIdentity::X
48 }
49 'Y' => {
50 chars.next();
51 NotIdentity::Y
52 }
53 'Z' => {
54 chars.next();
55 NotIdentity::Z
56 }
57 _ => Err(anyhow::anyhow!("Expected X, Y, or Z in []"))?,
58 };
59 alter.insert(op);
60 } let mut alter_iter = alter.iter();
63 match alter.len() {
64 1 => OpPattern::Single(*alter_iter.next().unwrap()),
65 2 => OpPattern::Double(
66 *alter_iter.next().unwrap(),
67 *alter_iter.next().unwrap(),
68 ),
69 3 => OpPattern::AnyNonIdentity,
70 _ => Err(anyhow::anyhow!("Too many Pauli characters in pattern"))?,
71 }
72 }
73 '_' => OpPattern::AnyPauliOrIdentity,
74 'X' => OpPattern::Single(NotIdentity::X),
75 'Y' => OpPattern::Single(NotIdentity::Y),
76 'Z' => OpPattern::Single(NotIdentity::Z),
77 _ => Err(anyhow::anyhow!("Expected X, Y, or Z in Pauli pattern"))?,
78 }; let op = match chars.peek() {
81 Some('?') => {
82 chars.next();
83 op.add_identity()
84 }
85 _ => op,
86 };
87
88 match chars.peek() {
89 Some('*') => {
90 chars.next(); patterns.push(Decorated::Star(op));
92 }
93 Some('{') => {
94 chars.next(); let mut num = String::new();
96 while let Some(ch) = chars.peek() {
97 if ch.is_ascii_digit() {
98 num.push(*ch);
99 chars.next();
100 } else if *ch == '}' {
101 chars.next(); break;
103 } else {
104 Err(anyhow::anyhow!("Expected digit or '}}' after '{{'"))?;
105 }
106 }
107 let count = num.parse::<usize>()?;
108 patterns.push(Decorated::Repeat(op, count));
109 }
110 Some(x) if x.is_ascii_digit() => {
111 let mut num = String::new();
112 while let Some(ch) = chars.peek() {
113 if ch.is_ascii_digit() {
114 num.push(*ch);
115 chars.next();
116 } else {
117 break;
118 }
119 }
120 let position = num.parse::<usize>()?;
121 patterns.push(Decorated::Position(op, position));
122 }
123 _ => Err(anyhow::anyhow!("Expected '*' or digit after Pauli pattern"))?,
124 }
125 }
126 Ok(PauliPattern(patterns))
127 }
128
129 pub(crate) fn iter(&self) -> impl Iterator<Item = &Decorated> {
130 self.0.iter()
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use Decorated::*;
138 use NotIdentity::*;
139 use OpPattern::*;
140
141 #[test]
142 fn test_parse_patterns() {
143 let answer = PauliPattern::parse("X1Y2Z3").unwrap();
144 let expect = PauliPattern(vec![
145 Position(Single(X), 1),
146 Position(Single(Y), 2),
147 Position(Single(Z), 3),
148 ]);
149 assert_eq!(answer, expect);
150
151 let answer = PauliPattern::parse("[XY]1Y2_3").unwrap();
152 let expect = PauliPattern(vec![
153 Position(Double(X, Y), 1),
154 Position(Single(Y), 2),
155 Position(AnyPauliOrIdentity, 3),
156 ]);
157 assert_eq!(answer, expect);
158
159 let answer = PauliPattern::parse("X?1Y2Z3").unwrap();
160 let expect = PauliPattern(vec![
161 Position(SingleOrIdentity(X), 1),
162 Position(Single(Y), 2),
163 Position(Single(Z), 3),
164 ]);
165 assert_eq!(answer, expect);
166
167 let answer = PauliPattern::parse("[XY]*Z5").unwrap();
168 let expect = PauliPattern(vec![Star(Double(X, Y)), Position(Single(Z), 5)]);
169 assert_eq!(answer, expect);
170
171 let answer = PauliPattern::parse("[XY]{3}Z5").unwrap();
172 let expect = PauliPattern(vec![Repeat(Double(X, Y), 3), Position(Single(Z), 5)]);
173 assert_eq!(answer, expect);
174 }
175
176 #[test]
177 #[cfg(feature = "bincode")]
178 fn test_bincode() {
179 use bincode;
180 let pat = PauliPattern::parse("[XY]{2}Z3").unwrap();
181 let mut encoded = [0u8; 100];
182 bincode::encode_into_slice(&pat, &mut encoded[..], bincode::config::standard()).unwrap();
183 let (decoded, _) =
184 bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap();
185 assert_eq!(pat, decoded);
186 }
187}