use crate::{DeviceError, DeviceResult};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum NeutralAtomGateType {
SingleQubitRotation,
RydbergExcitation,
RydbergBlockade,
GlobalRydberg,
TweezerMovement,
HyperfineManipulation,
Measurement,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NeutralAtomGateParams {
pub gate_type: NeutralAtomGateType,
pub target_atoms: Vec<usize>,
pub duration: Duration,
pub parameters: HashMap<String, f64>,
pub metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SingleQubitRotationParams {
pub angle: f64,
pub axis: RotationAxis,
pub laser_power: f64,
pub pulse_duration: Duration,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum RotationAxis {
X,
Y,
Z,
Arbitrary { x: f64, y: f64, z: f64 },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RydbergExcitationParams {
pub atom_index: usize,
pub excitation_time: Duration,
pub laser_power: f64,
pub detuning: f64,
pub rabi_frequency: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RydbergBlockadeParams {
pub control_atom: usize,
pub target_atom: usize,
pub blockade_strength: f64,
pub interaction_time: Duration,
pub phase: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GlobalRydbergParams {
pub operation_type: String,
pub laser_power: f64,
pub pulse_duration: Duration,
pub phase: f64,
pub frequency_sweep: Option<FrequencySweepParams>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrequencySweepParams {
pub start_frequency: f64,
pub end_frequency: f64,
pub sweep_rate: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TweezerMovementParams {
pub atom_index: usize,
pub start_position: (f64, f64, f64),
pub end_position: (f64, f64, f64),
pub movement_time: Duration,
pub trajectory: MovementTrajectory,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum MovementTrajectory {
Linear,
Smooth,
Custom(Vec<(f64, f64, f64)>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HyperfineManipulationParams {
pub atom_index: usize,
pub initial_state: String,
pub target_state: String,
pub microwave_frequency: f64,
pub pulse_duration: Duration,
pub pulse_power: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MeasurementParams {
pub target_atoms: Vec<usize>,
pub measurement_type: MeasurementType,
pub integration_time: Duration,
pub basis: MeasurementBasis,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MeasurementType {
StateDetection,
Fluorescence,
Ionization,
Correlation,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MeasurementBasis {
Computational,
X,
Y,
Custom(String),
}
pub struct NeutralAtomGateBuilder {
gate_type: Option<NeutralAtomGateType>,
target_atoms: Vec<usize>,
duration: Option<Duration>,
parameters: HashMap<String, f64>,
metadata: HashMap<String, String>,
}
impl NeutralAtomGateBuilder {
pub fn new() -> Self {
Self {
gate_type: None,
target_atoms: Vec::new(),
duration: None,
parameters: HashMap::new(),
metadata: HashMap::new(),
}
}
#[must_use]
pub const fn gate_type(mut self, gate_type: NeutralAtomGateType) -> Self {
self.gate_type = Some(gate_type);
self
}
#[must_use]
pub fn target_atoms(mut self, atoms: &[usize]) -> Self {
self.target_atoms.extend_from_slice(atoms);
self
}
#[must_use]
pub const fn duration(mut self, duration: Duration) -> Self {
self.duration = Some(duration);
self
}
#[must_use]
pub fn parameter(mut self, key: &str, value: f64) -> Self {
self.parameters.insert(key.to_string(), value);
self
}
#[must_use]
pub fn metadata(mut self, key: &str, value: &str) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
pub fn build(self) -> DeviceResult<NeutralAtomGateParams> {
let gate_type = self
.gate_type
.ok_or_else(|| DeviceError::InvalidInput("Gate type must be specified".to_string()))?;
let duration = self.duration.ok_or_else(|| {
DeviceError::InvalidInput("Gate duration must be specified".to_string())
})?;
if self.target_atoms.is_empty() {
return Err(DeviceError::InvalidInput(
"At least one target atom must be specified".to_string(),
));
}
Ok(NeutralAtomGateParams {
gate_type,
target_atoms: self.target_atoms,
duration,
parameters: self.parameters,
metadata: self.metadata,
})
}
}
impl Default for NeutralAtomGateBuilder {
fn default() -> Self {
Self::new()
}
}
pub fn validate_gate_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
if params.target_atoms.is_empty() {
return Err(DeviceError::InvalidInput(
"Gate operation must have at least one target atom".to_string(),
));
}
if params.duration.is_zero() {
return Err(DeviceError::InvalidInput(
"Gate duration must be positive".to_string(),
));
}
match params.gate_type {
NeutralAtomGateType::SingleQubitRotation => {
validate_single_qubit_rotation_params(params)?;
}
NeutralAtomGateType::RydbergExcitation => {
validate_rydberg_excitation_params(params)?;
}
NeutralAtomGateType::RydbergBlockade => {
validate_rydberg_blockade_params(params)?;
}
NeutralAtomGateType::TweezerMovement => {
validate_tweezer_movement_params(params)?;
}
_ => {} }
Ok(())
}
fn validate_single_qubit_rotation_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
if params.target_atoms.len() != 1 {
return Err(DeviceError::InvalidInput(
"Single-qubit rotation must target exactly one atom".to_string(),
));
}
if !params.parameters.contains_key("angle") {
return Err(DeviceError::InvalidInput(
"Single-qubit rotation must specify rotation angle".to_string(),
));
}
Ok(())
}
fn validate_rydberg_excitation_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
if params.target_atoms.len() != 1 {
return Err(DeviceError::InvalidInput(
"Rydberg excitation must target exactly one atom".to_string(),
));
}
if !params.parameters.contains_key("laser_power") {
return Err(DeviceError::InvalidInput(
"Rydberg excitation must specify laser power".to_string(),
));
}
Ok(())
}
fn validate_rydberg_blockade_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
if params.target_atoms.len() != 2 {
return Err(DeviceError::InvalidInput(
"Rydberg blockade must target exactly two atoms".to_string(),
));
}
if !params.parameters.contains_key("blockade_strength") {
return Err(DeviceError::InvalidInput(
"Rydberg blockade must specify blockade strength".to_string(),
));
}
Ok(())
}
fn validate_tweezer_movement_params(params: &NeutralAtomGateParams) -> DeviceResult<()> {
if params.target_atoms.len() != 1 {
return Err(DeviceError::InvalidInput(
"Tweezer movement must target exactly one atom".to_string(),
));
}
let required_params = ["start_x", "start_y", "start_z", "end_x", "end_y", "end_z"];
for param in &required_params {
if !params.parameters.contains_key(*param) {
return Err(DeviceError::InvalidInput(format!(
"Tweezer movement must specify {param}"
)));
}
}
Ok(())
}
pub fn create_single_qubit_rotation(
atom_index: usize,
angle: f64,
axis: RotationAxis,
duration: Duration,
) -> DeviceResult<NeutralAtomGateParams> {
let axis_str = match axis {
RotationAxis::X => "x".to_string(),
RotationAxis::Y => "y".to_string(),
RotationAxis::Z => "z".to_string(),
RotationAxis::Arbitrary { x, y, z } => format!("arbitrary_{x}_{y}_{z}"),
};
NeutralAtomGateBuilder::new()
.gate_type(NeutralAtomGateType::SingleQubitRotation)
.target_atoms(&[atom_index])
.duration(duration)
.parameter("angle", angle)
.metadata("axis", &axis_str)
.build()
}
pub fn create_rydberg_excitation(
atom_index: usize,
laser_power: f64,
excitation_time: Duration,
detuning: f64,
) -> DeviceResult<NeutralAtomGateParams> {
NeutralAtomGateBuilder::new()
.gate_type(NeutralAtomGateType::RydbergExcitation)
.target_atoms(&[atom_index])
.duration(excitation_time)
.parameter("laser_power", laser_power)
.parameter("detuning", detuning)
.build()
}
pub fn create_rydberg_blockade(
control_atom: usize,
target_atom: usize,
blockade_strength: f64,
interaction_time: Duration,
) -> DeviceResult<NeutralAtomGateParams> {
NeutralAtomGateBuilder::new()
.gate_type(NeutralAtomGateType::RydbergBlockade)
.target_atoms(&[control_atom, target_atom])
.duration(interaction_time)
.parameter("blockade_strength", blockade_strength)
.parameter("control_atom", control_atom as f64)
.parameter("target_atom", target_atom as f64)
.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gate_builder() {
let gate = NeutralAtomGateBuilder::new()
.gate_type(NeutralAtomGateType::SingleQubitRotation)
.target_atoms(&[0])
.duration(Duration::from_micros(100))
.parameter("angle", std::f64::consts::PI)
.build()
.expect("Failed to build single-qubit rotation gate");
assert_eq!(gate.gate_type, NeutralAtomGateType::SingleQubitRotation);
assert_eq!(gate.target_atoms, vec![0]);
assert_eq!(gate.duration, Duration::from_micros(100));
assert_eq!(gate.parameters.get("angle"), Some(&std::f64::consts::PI));
}
#[test]
fn test_gate_validation() {
let gate = NeutralAtomGateParams {
gate_type: NeutralAtomGateType::SingleQubitRotation,
target_atoms: vec![0],
duration: Duration::from_micros(100),
parameters: [("angle".to_string(), std::f64::consts::PI)].into(),
metadata: HashMap::new(),
};
assert!(validate_gate_params(&gate).is_ok());
}
#[test]
fn test_create_single_qubit_rotation() {
let gate = create_single_qubit_rotation(
0,
std::f64::consts::PI,
RotationAxis::X,
Duration::from_micros(100),
)
.expect("Failed to create single-qubit rotation gate");
assert_eq!(gate.gate_type, NeutralAtomGateType::SingleQubitRotation);
assert_eq!(gate.target_atoms, vec![0]);
assert_eq!(gate.parameters.get("angle"), Some(&std::f64::consts::PI));
}
}