Skip to content

Commit cf32f16

Browse files
committed
Add skeleton StandardGate→BitTerm generator mapping
1 parent c923aba commit cf32f16

2 files changed

Lines changed: 109 additions & 0 deletions

File tree

crates/quantum_info/src/sparse_observable/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
// copyright notice, and modified files need to carry a notice indicating
1111
// that they have been altered from the originals.
1212

13+
pub mod standard_generators;
14+
1315
mod lookup;
1416

1517
use hashbrown::HashSet;
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// src/sparse_observable/standard_generators.rs
2+
3+
use num_complex::Complex64;
4+
use super::BitTerm;
5+
use super::SparseObservable;
6+
7+
// Temporary: minimal set of standard 1‑qubit gates we care about here.
8+
// This can be wired up to the real gate enum later.
9+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10+
pub enum StandardGate {
11+
Id,
12+
Rx,
13+
Ry,
14+
Rz,
15+
H,
16+
S,
17+
Sdg,
18+
// TODO: extend if/when we need more.
19+
}
20+
21+
impl StandardGate {
22+
pub const NUM_VARIANTS: usize = 7;
23+
24+
#[inline]
25+
pub fn as_index(self) -> usize {
26+
self as usize
27+
}
28+
}
29+
30+
// StandardGate → Pauli generator(s) as BitTerms.
31+
// Empty slice = “no generator, fall back to the old path”.
32+
static GENERATORS: [&[BitTerm]; StandardGate::NUM_VARIANTS] = {
33+
use BitTerm::*;
34+
[
35+
// Id
36+
&[],
37+
38+
// Rx
39+
&[X],
40+
41+
// Ry
42+
&[Y],
43+
44+
// Rz
45+
&[Z],
46+
47+
// H (roughly X+Z in this picture)
48+
&[X, Z],
49+
50+
// S
51+
&[Z],
52+
53+
// Sdg
54+
&[Z],
55+
]
56+
};
57+
58+
/// Return an observable for the generator of `gate`, if we have one.
59+
///
60+
/// `None` means “no special handling, use the generic commutation path”.
61+
pub fn generator_observable(gate: StandardGate) -> Option<SparseObservable> {
62+
let idx = gate.as_index();
63+
let terms = GENERATORS.get(idx)?;
64+
if terms.is_empty() {
65+
return None;
66+
}
67+
68+
// For now assume a single-qubit generator acting on 1 qubit.
69+
// You can generalize later if needed.
70+
let num_qubits = 1;
71+
72+
// One coefficient per term, all +1 for now.
73+
let coeffs = vec![Complex64::new(1.0, 0.0); terms.len()];
74+
75+
// Flatten the BitTerm slice into a Vec<BitTerm>.
76+
let bit_terms: Vec<BitTerm> = terms.to_vec();
77+
78+
// Each term uses one BitTerm; indices are 0,1,2,... and boundaries are
79+
// [0, 1, 2, ..., len].
80+
let indices: Vec<u32> = (0..bit_terms.len() as u32).collect();
81+
let boundaries: Vec<usize> = (0..=bit_terms.len()).collect();
82+
83+
// Safe constructor; unwrap is fine here because we control the layout.
84+
let obs = SparseObservable::new(
85+
num_qubits,
86+
coeffs,
87+
bit_terms,
88+
indices,
89+
boundaries,
90+
)
91+
.expect("invalid generator observable layout");
92+
93+
Some(obs)
94+
}
95+
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::*;
100+
101+
#[test]
102+
fn rx_has_some_generator() {
103+
let obs = generator_observable(StandardGate::Rx)
104+
.expect("Rx should have a generator");
105+
assert!(!obs.bit_terms().is_empty());
106+
}
107+
}

0 commit comments

Comments
 (0)