ppvm_pauli_word/pattern/
contains.rs1use super::data::{Decorated, NotIdentity, OpPattern, PauliPattern};
5use ppvm_traits::char::Pauli;
6use ppvm_traits::traits::PauliIter;
7use std::iter::Peekable;
8
9pub trait Contains<T> {
15 fn contains(&self, item: &T) -> bool;
17}
18
19impl Contains<Pauli> for NotIdentity {
20 fn contains(&self, item: &Pauli) -> bool {
21 (*self as u8) == (*item as u8)
22 }
23}
24
25impl Contains<Pauli> for OpPattern {
26 fn contains(&self, item: &Pauli) -> bool {
27 match self {
28 OpPattern::Identity => *item == Pauli::I,
29 OpPattern::Single(op) => op.contains(item),
30 OpPattern::Double(left, right) => left.contains(item) || right.contains(item),
31 OpPattern::AnyNonIdentity => {
32 *item == Pauli::X || *item == Pauli::Y || *item == Pauli::Z
33 }
34 OpPattern::SingleOrIdentity(op) => op.contains(item) || *item == Pauli::I,
35 OpPattern::DoubleOrIdentity(left, right) => {
36 left.contains(item) || right.contains(item) || *item == Pauli::I
37 }
38 OpPattern::AnyPauliOrIdentity => *item == Pauli::I,
39 }
40 }
41}
42
43enum Step {
44 NextPattern,
45 DontMatch,
46}
47
48fn match_position<I: Iterator<Item = (usize, Pauli)>>(
49 chars: &mut Peekable<I>,
50 pattern: &OpPattern,
51 pos: &usize,
52) -> Step {
53 for (ch_pos, ch) in chars.by_ref() {
54 if ch_pos == *pos {
55 if pattern.contains(&ch) {
56 return Step::NextPattern;
57 } else {
58 return Step::DontMatch;
59 }
60 } else if ch == Pauli::I {
61 continue;
62 } else {
63 return Step::DontMatch;
66 }
67 }
68 Step::DontMatch
70}
71
72fn match_star<I: Iterator<Item = (usize, Pauli)>>(
73 chars: &mut Peekable<I>,
74 pattern: &OpPattern,
75) -> Step {
76 while let Some((_, ch)) = chars.peek() {
77 if pattern.contains(ch) {
78 chars.next();
79 continue;
80 } else {
81 return Step::NextPattern;
84 }
85 }
86 Step::NextPattern
88}
89
90fn match_repeat<I: Iterator<Item = (usize, Pauli)>>(
91 chars: &mut Peekable<I>,
92 pattern: &OpPattern,
93 count: usize,
94) -> Step {
95 let mut matched = 0;
96 while let Some((_, ch)) = chars.peek() {
97 if pattern.contains(ch) {
98 chars.next();
99 matched += 1;
100 if matched == count {
101 return Step::NextPattern;
102 }
103 } else {
104 if matched < count {
106 return Step::DontMatch;
107 } else {
108 return Step::NextPattern;
109 }
110 }
111 }
112 if matched == count {
114 Step::NextPattern
115 } else {
116 Step::DontMatch
117 }
118}
119
120impl<W> Contains<W> for PauliPattern
121where
122 W: PauliIter,
123{
124 fn contains(&self, item: &W) -> bool {
125 let mut chars = item.iter().enumerate().peekable();
126 let patterns = self.iter();
127 for current in patterns {
128 let step = match current {
129 Decorated::Position(op, pos) => match_position(&mut chars, op, pos),
130 Decorated::Star(op) => match_star(&mut chars, op),
131 Decorated::Repeat(op, count) => match_repeat(&mut chars, op, *count),
132 };
133
134 match step {
135 Step::NextPattern => continue,
136 Step::DontMatch => return false,
137 }
138 }
139
140 for (_, ch) in chars {
142 if ch == Pauli::I {
143 continue;
144 } else {
145 return false;
147 }
148 }
149 true
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::word::PauliWord;
157
158 #[test]
159 fn test_match_not_ident() {
160 assert!(NotIdentity::X.contains(&Pauli::X));
161 assert!(NotIdentity::Y.contains(&Pauli::Y));
162 assert!(NotIdentity::Z.contains(&Pauli::Z));
163 }
164
165 #[test]
166 fn test_match() {
167 let pat = PauliPattern::parse("X0Y1Z2").unwrap();
168 let word: PauliWord<u64> = "XYZ".into();
169 assert!(pat.contains(&word));
170
171 let pat = PauliPattern::parse("X?0Y1Z2").unwrap();
172 let word: PauliWord<u64> = "XYZ".into();
173 assert!(pat.contains(&word));
174 let word: PauliWord<u64> = "IYZ".into();
175 assert!(pat.contains(&word));
176
177 let pat = PauliPattern::parse("[XY]0Y1Z2").unwrap();
178 let word: PauliWord<u64> = "XYZ".into();
179 assert!(pat.contains(&word));
180 let word: PauliWord<u64> = "YYZ".into();
181 assert!(pat.contains(&word));
182
183 let pat = PauliPattern::parse("[XY]?0Y1Z2").unwrap();
184 let word: PauliWord<u64> = "XYZ".into();
185 assert!(pat.contains(&word));
186 let word: PauliWord<u64> = "YYZ".into();
187 assert!(pat.contains(&word));
188 let word: PauliWord<u64> = "IYZ".into();
189 assert!(pat.contains(&word));
190
191 let pat = PauliPattern::parse("[XY]?*").unwrap();
192 let word: PauliWord<u64> = "XYX".into();
193 assert!(pat.contains(&word));
194 let word: PauliWord<u64> = "YYX".into();
195 assert!(pat.contains(&word));
196 let word: PauliWord<u64> = "IYX".into();
197 assert!(pat.contains(&word));
198
199 let pat = PauliPattern::parse("[XY]?{2}Z2").unwrap();
200 let word: PauliWord<u64> = "XYZ".into();
201 assert!(pat.contains(&word));
202 let word: PauliWord<u64> = "YYZ".into();
203 assert!(pat.contains(&word));
204 let word: PauliWord<u64> = "IYZ".into();
205 assert!(pat.contains(&word));
206 }
207
208 #[test]
209 fn test_not_match() {
210 let pat: PauliPattern = "Z?*".into();
211 let word: PauliWord<u64> = "XYY".into();
212 assert!(!pat.contains(&word));
213 }
214}