quantrs2_device/neutral_atom/
gate_operations.rs

1//! Gate operations for neutral atom quantum devices
2//!
3//! This module provides implementations of quantum gate operations
4//! specific to neutral atom systems, including Rydberg gates,
5//! optical tweezer manipulations, and hyperfine state operations.
6
7use crate::{DeviceError, DeviceResult};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::time::Duration;
11
12/// Gate operation types for neutral atoms
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub enum NeutralAtomGateType {
15    /// Single-qubit rotation gates
16    SingleQubitRotation,
17    /// Rydberg excitation gate
18    RydbergExcitation,
19    /// Rydberg blockade gate
20    RydbergBlockade,
21    /// Global Rydberg gate
22    GlobalRydberg,
23    /// Optical tweezer movement
24    TweezerMovement,
25    /// Hyperfine state manipulation
26    HyperfineManipulation,
27    /// Measurement operation
28    Measurement,
29}
30
31/// Parameters for neutral atom gate operations
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct NeutralAtomGateParams {
34    /// Gate type
35    pub gate_type: NeutralAtomGateType,
36    /// Target atom indices
37    pub target_atoms: Vec<usize>,
38    /// Gate duration
39    pub duration: Duration,
40    /// Gate-specific parameters
41    pub parameters: HashMap<String, f64>,
42    /// Additional metadata
43    pub metadata: HashMap<String, String>,
44}
45
46/// Single-qubit rotation gate parameters
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct SingleQubitRotationParams {
49    /// Rotation angle (radians)
50    pub angle: f64,
51    /// Rotation axis
52    pub axis: RotationAxis,
53    /// Laser power (mW)
54    pub laser_power: f64,
55    /// Pulse duration
56    pub pulse_duration: Duration,
57}
58
59/// Rotation axis for single-qubit gates
60#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
61pub enum RotationAxis {
62    /// X-axis rotation
63    X,
64    /// Y-axis rotation
65    Y,
66    /// Z-axis rotation
67    Z,
68    /// Arbitrary axis
69    Arbitrary { x: f64, y: f64, z: f64 },
70}
71
72/// Rydberg excitation gate parameters
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct RydbergExcitationParams {
75    /// Target atom index
76    pub atom_index: usize,
77    /// Excitation time
78    pub excitation_time: Duration,
79    /// Laser power (mW)
80    pub laser_power: f64,
81    /// Detuning from resonance (MHz)
82    pub detuning: f64,
83    /// Rabi frequency (MHz)
84    pub rabi_frequency: f64,
85}
86
87/// Rydberg blockade gate parameters
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct RydbergBlockadeParams {
90    /// Control atom index
91    pub control_atom: usize,
92    /// Target atom index
93    pub target_atom: usize,
94    /// Blockade strength (MHz)
95    pub blockade_strength: f64,
96    /// Interaction time
97    pub interaction_time: Duration,
98    /// Gate phase
99    pub phase: f64,
100}
101
102/// Global Rydberg operation parameters
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct GlobalRydbergParams {
105    /// Operation type
106    pub operation_type: String,
107    /// Laser power (mW)
108    pub laser_power: f64,
109    /// Pulse duration
110    pub pulse_duration: Duration,
111    /// Phase (radians)
112    pub phase: f64,
113    /// Frequency sweep parameters
114    pub frequency_sweep: Option<FrequencySweepParams>,
115}
116
117/// Frequency sweep parameters
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct FrequencySweepParams {
120    /// Start frequency (MHz)
121    pub start_frequency: f64,
122    /// End frequency (MHz)
123    pub end_frequency: f64,
124    /// Sweep rate (MHz/μs)
125    pub sweep_rate: f64,
126}
127
128/// Optical tweezer movement parameters
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct TweezerMovementParams {
131    /// Atom index to move
132    pub atom_index: usize,
133    /// Start position (x, y, z) in micrometers
134    pub start_position: (f64, f64, f64),
135    /// End position (x, y, z) in micrometers
136    pub end_position: (f64, f64, f64),
137    /// Movement time
138    pub movement_time: Duration,
139    /// Movement trajectory
140    pub trajectory: MovementTrajectory,
141}
142
143/// Movement trajectory types
144#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
145pub enum MovementTrajectory {
146    /// Linear movement
147    Linear,
148    /// Smooth acceleration/deceleration
149    Smooth,
150    /// Custom trajectory with waypoints
151    Custom(Vec<(f64, f64, f64)>),
152}
153
154/// Hyperfine state manipulation parameters
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct HyperfineManipulationParams {
157    /// Target atom index
158    pub atom_index: usize,
159    /// Initial hyperfine state
160    pub initial_state: String,
161    /// Target hyperfine state
162    pub target_state: String,
163    /// Microwave frequency (MHz)
164    pub microwave_frequency: f64,
165    /// Pulse duration
166    pub pulse_duration: Duration,
167    /// Pulse power (dBm)
168    pub pulse_power: f64,
169}
170
171/// Measurement operation parameters
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct MeasurementParams {
174    /// Atoms to measure
175    pub target_atoms: Vec<usize>,
176    /// Measurement type
177    pub measurement_type: MeasurementType,
178    /// Integration time
179    pub integration_time: Duration,
180    /// Measurement basis
181    pub basis: MeasurementBasis,
182}
183
184/// Measurement types
185#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
186pub enum MeasurementType {
187    /// Standard state detection
188    StateDetection,
189    /// Fluorescence measurement
190    Fluorescence,
191    /// Ionization measurement
192    Ionization,
193    /// Correlation measurement
194    Correlation,
195}
196
197/// Measurement basis
198#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
199pub enum MeasurementBasis {
200    /// Computational basis (|0⟩, |1⟩)
201    Computational,
202    /// X basis (|+⟩, |-⟩)
203    X,
204    /// Y basis (|+i⟩, |-i⟩)
205    Y,
206    /// Custom basis
207    Custom(String),
208}
209
210/// Gate operation builder
211pub struct NeutralAtomGateBuilder {
212    gate_type: Option<NeutralAtomGateType>,
213    target_atoms: Vec<usize>,
214    duration: Option<Duration>,
215    parameters: HashMap<String, f64>,
216    metadata: HashMap<String, String>,
217}
218
219impl NeutralAtomGateBuilder {
220    /// Create a new gate builder
221    pub fn new() -> Self {
222        Self {
223            gate_type: None,
224            target_atoms: Vec::new(),
225            duration: None,
226            parameters: HashMap::new(),
227            metadata: HashMap::new(),
228        }
229    }
230
231    /// Set the gate type
232    #[must_use]
233    pub const fn gate_type(mut self, gate_type: NeutralAtomGateType) -> Self {
234        self.gate_type = Some(gate_type);
235        self
236    }
237
238    /// Add target atoms
239    #[must_use]
240    pub fn target_atoms(mut self, atoms: &[usize]) -> Self {
241        self.target_atoms.extend_from_slice(atoms);
242        self
243    }
244
245    /// Set gate duration
246    #[must_use]
247    pub const fn duration(mut self, duration: Duration) -> Self {
248        self.duration = Some(duration);
249        self
250    }
251
252    /// Add a parameter
253    #[must_use]
254    pub fn parameter(mut self, key: &str, value: f64) -> Self {
255        self.parameters.insert(key.to_string(), value);
256        self
257    }
258
259    /// Add metadata
260    #[must_use]
261    pub fn metadata(mut self, key: &str, value: &str) -> Self {
262        self.metadata.insert(key.to_string(), value.to_string());
263        self
264    }
265
266    /// Build the gate parameters
267    pub fn build(self) -> DeviceResult<NeutralAtomGateParams> {
268        let gate_type = self
269            .gate_type
270            .ok_or_else(|| DeviceError::InvalidInput("Gate type must be specified".to_string()))?;
271
272        let duration = self.duration.ok_or_else(|| {
273            DeviceError::InvalidInput("Gate duration must be specified".to_string())
274        })?;
275
276        if self.target_atoms.is_empty() {
277            return Err(DeviceError::InvalidInput(
278                "At least one target atom must be specified".to_string(),
279            ));
280        }
281
282        Ok(NeutralAtomGateParams {
283            gate_type,
284            target_atoms: self.target_atoms,
285            duration,
286            parameters: self.parameters,
287            metadata: self.metadata,
288        })
289    }
290}
291
292impl Default for NeutralAtomGateBuilder {
293    fn default() -> Self {
294        Self::new()
295    }
296}
297
298/// Validate gate operation parameters
299pub fn validate_gate_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
300    // Check that target atoms are valid
301    if params.target_atoms.is_empty() {
302        return Err(DeviceError::InvalidInput(
303            "Gate operation must have at least one target atom".to_string(),
304        ));
305    }
306
307    // Check duration is positive
308    if params.duration.is_zero() {
309        return Err(DeviceError::InvalidInput(
310            "Gate duration must be positive".to_string(),
311        ));
312    }
313
314    // Validate gate-specific parameters
315    match params.gate_type {
316        NeutralAtomGateType::SingleQubitRotation => {
317            validate_single_qubit_rotation_params(params)?;
318        }
319        NeutralAtomGateType::RydbergExcitation => {
320            validate_rydberg_excitation_params(params)?;
321        }
322        NeutralAtomGateType::RydbergBlockade => {
323            validate_rydberg_blockade_params(params)?;
324        }
325        NeutralAtomGateType::TweezerMovement => {
326            validate_tweezer_movement_params(params)?;
327        }
328        _ => {} // Other gate types have their own validation
329    }
330
331    Ok(())
332}
333
334fn validate_single_qubit_rotation_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
335    if params.target_atoms.len() != 1 {
336        return Err(DeviceError::InvalidInput(
337            "Single-qubit rotation must target exactly one atom".to_string(),
338        ));
339    }
340
341    if !params.parameters.contains_key("angle") {
342        return Err(DeviceError::InvalidInput(
343            "Single-qubit rotation must specify rotation angle".to_string(),
344        ));
345    }
346
347    Ok(())
348}
349
350fn validate_rydberg_excitation_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
351    if params.target_atoms.len() != 1 {
352        return Err(DeviceError::InvalidInput(
353            "Rydberg excitation must target exactly one atom".to_string(),
354        ));
355    }
356
357    if !params.parameters.contains_key("laser_power") {
358        return Err(DeviceError::InvalidInput(
359            "Rydberg excitation must specify laser power".to_string(),
360        ));
361    }
362
363    Ok(())
364}
365
366fn validate_rydberg_blockade_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
367    if params.target_atoms.len() != 2 {
368        return Err(DeviceError::InvalidInput(
369            "Rydberg blockade must target exactly two atoms".to_string(),
370        ));
371    }
372
373    if !params.parameters.contains_key("blockade_strength") {
374        return Err(DeviceError::InvalidInput(
375            "Rydberg blockade must specify blockade strength".to_string(),
376        ));
377    }
378
379    Ok(())
380}
381
382fn validate_tweezer_movement_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
383    if params.target_atoms.len() != 1 {
384        return Err(DeviceError::InvalidInput(
385            "Tweezer movement must target exactly one atom".to_string(),
386        ));
387    }
388
389    let required_params = ["start_x", "start_y", "start_z", "end_x", "end_y", "end_z"];
390    for param in &required_params {
391        if !params.parameters.contains_key(*param) {
392            return Err(DeviceError::InvalidInput(format!(
393                "Tweezer movement must specify {param}"
394            )));
395        }
396    }
397
398    Ok(())
399}
400
401/// Create a single-qubit rotation gate
402pub fn create_single_qubit_rotation(
403    atom_index: usize,
404    angle: f64,
405    axis: RotationAxis,
406    duration: Duration,
407) -> DeviceResult<NeutralAtomGateParams> {
408    let axis_str = match axis {
409        RotationAxis::X => "x".to_string(),
410        RotationAxis::Y => "y".to_string(),
411        RotationAxis::Z => "z".to_string(),
412        RotationAxis::Arbitrary { x, y, z } => format!("arbitrary_{x}_{y}_{z}"),
413    };
414
415    NeutralAtomGateBuilder::new()
416        .gate_type(NeutralAtomGateType::SingleQubitRotation)
417        .target_atoms(&[atom_index])
418        .duration(duration)
419        .parameter("angle", angle)
420        .metadata("axis", &axis_str)
421        .build()
422}
423
424/// Create a Rydberg excitation gate
425pub fn create_rydberg_excitation(
426    atom_index: usize,
427    laser_power: f64,
428    excitation_time: Duration,
429    detuning: f64,
430) -> DeviceResult<NeutralAtomGateParams> {
431    NeutralAtomGateBuilder::new()
432        .gate_type(NeutralAtomGateType::RydbergExcitation)
433        .target_atoms(&[atom_index])
434        .duration(excitation_time)
435        .parameter("laser_power", laser_power)
436        .parameter("detuning", detuning)
437        .build()
438}
439
440/// Create a Rydberg blockade gate
441pub fn create_rydberg_blockade(
442    control_atom: usize,
443    target_atom: usize,
444    blockade_strength: f64,
445    interaction_time: Duration,
446) -> DeviceResult<NeutralAtomGateParams> {
447    NeutralAtomGateBuilder::new()
448        .gate_type(NeutralAtomGateType::RydbergBlockade)
449        .target_atoms(&[control_atom, target_atom])
450        .duration(interaction_time)
451        .parameter("blockade_strength", blockade_strength)
452        .parameter("control_atom", control_atom as f64)
453        .parameter("target_atom", target_atom as f64)
454        .build()
455}
456
457#[cfg(test)]
458mod tests {
459    use super::*;
460
461    #[test]
462    fn test_gate_builder() {
463        let gate = NeutralAtomGateBuilder::new()
464            .gate_type(NeutralAtomGateType::SingleQubitRotation)
465            .target_atoms(&[0])
466            .duration(Duration::from_micros(100))
467            .parameter("angle", std::f64::consts::PI)
468            .build()
469            .expect("Failed to build single-qubit rotation gate");
470
471        assert_eq!(gate.gate_type, NeutralAtomGateType::SingleQubitRotation);
472        assert_eq!(gate.target_atoms, vec![0]);
473        assert_eq!(gate.duration, Duration::from_micros(100));
474        assert_eq!(gate.parameters.get("angle"), Some(&std::f64::consts::PI));
475    }
476
477    #[test]
478    fn test_gate_validation() {
479        let gate = NeutralAtomGateParams {
480            gate_type: NeutralAtomGateType::SingleQubitRotation,
481            target_atoms: vec![0],
482            duration: Duration::from_micros(100),
483            parameters: [("angle".to_string(), std::f64::consts::PI)].into(),
484            metadata: HashMap::new(),
485        };
486
487        assert!(validate_gate_params(&gate).is_ok());
488    }
489
490    #[test]
491    fn test_create_single_qubit_rotation() {
492        let gate = create_single_qubit_rotation(
493            0,
494            std::f64::consts::PI,
495            RotationAxis::X,
496            Duration::from_micros(100),
497        )
498        .expect("Failed to create single-qubit rotation gate");
499
500        assert_eq!(gate.gate_type, NeutralAtomGateType::SingleQubitRotation);
501        assert_eq!(gate.target_atoms, vec![0]);
502        assert_eq!(gate.parameters.get("angle"), Some(&std::f64::consts::PI));
503    }
504}