quantrs2_device/continuous_variable/
cluster_states.rs

1//! Cluster states for continuous variable quantum computing
2//!
3//! This module implements cluster state generation and manipulation for CV systems,
4//! enabling measurement-based quantum computing with continuous variables.
5
6use super::{CVDeviceConfig, CVGateSequence, Complex, GaussianState};
7use crate::{DeviceError, DeviceResult};
8use serde::{Deserialize, Serialize};
9use std::collections::{HashMap, HashSet};
10use std::f64::consts::PI;
11
12/// Types of CV cluster states
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum ClusterStateType {
15    /// Linear cluster (1D chain)
16    Linear,
17    /// Square lattice cluster (2D)
18    Square,
19    /// Hexagonal lattice cluster
20    Hexagonal,
21    /// Custom graph cluster
22    Custom { adjacency_matrix: Vec<Vec<bool>> },
23}
24
25/// Cluster state configuration
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct ClusterStateConfig {
28    /// Type of cluster state
29    pub cluster_type: ClusterStateType,
30    /// Number of modes in the cluster
31    pub num_modes: usize,
32    /// Squeezing parameter for initial squeezed states
33    pub squeezing_parameter: f64,
34    /// Entangling gate strength
35    pub entangling_strength: f64,
36    /// Graph structure (adjacency list)
37    pub graph_structure: HashMap<usize, Vec<usize>>,
38    /// Enable finite squeezing compensation
39    pub finite_squeezing_compensation: bool,
40}
41
42impl ClusterStateConfig {
43    /// Create a linear cluster configuration
44    pub fn linear(num_modes: usize, squeezing: f64) -> Self {
45        let mut graph_structure = HashMap::new();
46
47        for i in 0..num_modes {
48            let mut neighbors = Vec::new();
49            if i > 0 {
50                neighbors.push(i - 1);
51            }
52            if i < num_modes - 1 {
53                neighbors.push(i + 1);
54            }
55            graph_structure.insert(i, neighbors);
56        }
57
58        Self {
59            cluster_type: ClusterStateType::Linear,
60            num_modes,
61            squeezing_parameter: squeezing,
62            entangling_strength: 1.0,
63            graph_structure,
64            finite_squeezing_compensation: true,
65        }
66    }
67
68    /// Create a square lattice cluster configuration
69    pub fn square_lattice(width: usize, height: usize, squeezing: f64) -> Self {
70        let num_modes = width * height;
71        let mut graph_structure = HashMap::new();
72
73        for i in 0..height {
74            for j in 0..width {
75                let node = i * width + j;
76                let mut neighbors = Vec::new();
77
78                // Add horizontal neighbors
79                if j > 0 {
80                    neighbors.push(i * width + (j - 1));
81                }
82                if j < width - 1 {
83                    neighbors.push(i * width + (j + 1));
84                }
85
86                // Add vertical neighbors
87                if i > 0 {
88                    neighbors.push((i - 1) * width + j);
89                }
90                if i < height - 1 {
91                    neighbors.push((i + 1) * width + j);
92                }
93
94                graph_structure.insert(node, neighbors);
95            }
96        }
97
98        Self {
99            cluster_type: ClusterStateType::Square,
100            num_modes,
101            squeezing_parameter: squeezing,
102            entangling_strength: 1.0,
103            graph_structure,
104            finite_squeezing_compensation: true,
105        }
106    }
107
108    /// Create a custom cluster configuration
109    pub fn custom(adjacency_matrix: Vec<Vec<bool>>, squeezing: f64) -> DeviceResult<Self> {
110        let num_modes = adjacency_matrix.len();
111
112        // Validate adjacency matrix
113        for row in &adjacency_matrix {
114            if row.len() != num_modes {
115                return Err(DeviceError::InvalidInput(
116                    "Adjacency matrix must be square".to_string(),
117                ));
118            }
119        }
120
121        // Build graph structure from adjacency matrix
122        let mut graph_structure = HashMap::new();
123        for i in 0..num_modes {
124            let mut neighbors = Vec::new();
125            for j in 0..num_modes {
126                if adjacency_matrix[i][j] {
127                    neighbors.push(j);
128                }
129            }
130            graph_structure.insert(i, neighbors);
131        }
132
133        Ok(Self {
134            cluster_type: ClusterStateType::Custom { adjacency_matrix },
135            num_modes,
136            squeezing_parameter: squeezing,
137            entangling_strength: 1.0,
138            graph_structure,
139            finite_squeezing_compensation: true,
140        })
141    }
142}
143
144/// Cluster state generator
145pub struct ClusterStateGenerator {
146    /// Configuration
147    config: ClusterStateConfig,
148    /// Current cluster state
149    cluster_state: Option<GaussianState>,
150    /// Generation statistics
151    generation_stats: GenerationStatistics,
152}
153
154/// Statistics for cluster state generation
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct GenerationStatistics {
157    /// Total entangling gates applied
158    pub total_entangling_gates: usize,
159    /// Average entanglement per mode
160    pub average_entanglement: f64,
161    /// Nullifier violations (finite squeezing effects)
162    pub nullifier_violations: f64,
163    /// Generation fidelity
164    pub generation_fidelity: f64,
165    /// Time taken for generation (ms)
166    pub generation_time_ms: f64,
167}
168
169impl Default for GenerationStatistics {
170    fn default() -> Self {
171        Self {
172            total_entangling_gates: 0,
173            average_entanglement: 0.0,
174            nullifier_violations: 0.0,
175            generation_fidelity: 0.0,
176            generation_time_ms: 0.0,
177        }
178    }
179}
180
181impl ClusterStateGenerator {
182    /// Create a new cluster state generator
183    pub fn new(config: ClusterStateConfig) -> Self {
184        Self {
185            config,
186            cluster_state: None,
187            generation_stats: GenerationStatistics::default(),
188        }
189    }
190
191    /// Generate the cluster state
192    pub async fn generate_cluster_state(&mut self) -> DeviceResult<GaussianState> {
193        let start_time = std::time::Instant::now();
194
195        println!(
196            "Generating {} cluster state with {} modes",
197            match self.config.cluster_type {
198                ClusterStateType::Linear => "linear",
199                ClusterStateType::Square => "square lattice",
200                ClusterStateType::Hexagonal => "hexagonal",
201                ClusterStateType::Custom { .. } => "custom",
202            },
203            self.config.num_modes
204        );
205
206        // Step 1: Initialize with squeezed vacuum states
207        let mut state = self.initialize_squeezed_modes().await?;
208
209        // Step 2: Apply entangling gates according to graph structure
210        self.apply_entangling_gates(&mut state).await?;
211
212        // Step 3: Apply finite squeezing compensation if enabled
213        if self.config.finite_squeezing_compensation {
214            self.apply_squeezing_compensation(&mut state).await?;
215        }
216
217        // Step 4: Calculate generation statistics
218        self.calculate_generation_statistics(&state);
219
220        let generation_time = start_time.elapsed();
221        self.generation_stats.generation_time_ms = generation_time.as_millis() as f64;
222
223        println!(
224            "Cluster state generated in {:.2} ms with fidelity {:.3}",
225            self.generation_stats.generation_time_ms, self.generation_stats.generation_fidelity
226        );
227
228        self.cluster_state = Some(state.clone());
229        Ok(state)
230    }
231
232    /// Initialize all modes with squeezed vacuum states
233    async fn initialize_squeezed_modes(&mut self) -> DeviceResult<GaussianState> {
234        let squeezing_params = vec![self.config.squeezing_parameter; self.config.num_modes];
235        let squeezing_phases = vec![0.0; self.config.num_modes]; // All in x-quadrature
236
237        GaussianState::squeezed_vacuum_state(
238            self.config.num_modes,
239            squeezing_params,
240            squeezing_phases,
241        )
242        .map_err(|e| DeviceError::InvalidInput(format!("Failed to create squeezed states: {}", e)))
243    }
244
245    /// Apply entangling gates according to the graph structure
246    async fn apply_entangling_gates(&mut self, state: &mut GaussianState) -> DeviceResult<()> {
247        let mut gate_count = 0;
248
249        // Collect all edges to avoid double-counting
250        let mut edges = HashSet::new();
251        for (node, neighbors) in &self.config.graph_structure {
252            for neighbor in neighbors {
253                let edge = if node < neighbor {
254                    (*node, *neighbor)
255                } else {
256                    (*neighbor, *node)
257                };
258                edges.insert(edge);
259            }
260        }
261
262        println!("Applying {} entangling gates", edges.len());
263
264        // Apply controlled-Z gates for each edge
265        for (mode1, mode2) in edges {
266            self.apply_cv_cz_gate(state, mode1, mode2).await?;
267            gate_count += 1;
268
269            // Simulate some processing time
270            if gate_count % 10 == 0 {
271                tokio::time::sleep(std::time::Duration::from_millis(1)).await;
272            }
273        }
274
275        self.generation_stats.total_entangling_gates = gate_count;
276        Ok(())
277    }
278
279    /// Apply a continuous variable controlled-Z gate
280    async fn apply_cv_cz_gate(
281        &self,
282        state: &mut GaussianState,
283        mode1: usize,
284        mode2: usize,
285    ) -> DeviceResult<()> {
286        // CV controlled-Z gate is implemented via position-momentum coupling
287        // This creates correlation between x1 and p2, and p1 and x2
288
289        let strength = self.config.entangling_strength;
290
291        // Get current covariance matrix elements
292        let old_covar = state.covariancematrix.clone();
293
294        // Apply CZ transformation to covariance matrix
295        // CZ gate: exp(i*g*x1*x2) creates correlations
296
297        let i1_x = 2 * mode1; // x quadrature of mode 1
298        let i1_p = 2 * mode1 + 1; // p quadrature of mode 1
299        let i2_x = 2 * mode2; // x quadrature of mode 2
300        let i2_p = 2 * mode2 + 1; // p quadrature of mode 2
301
302        // CZ gate adds correlations between x1-p2 and p1-x2
303        state.covariancematrix[i1_x][i2_p] +=
304            strength * old_covar[i1_x][i1_x].sqrt() * old_covar[i2_p][i2_p].sqrt();
305        state.covariancematrix[i2_p][i1_x] +=
306            strength * old_covar[i1_x][i1_x].sqrt() * old_covar[i2_p][i2_p].sqrt();
307
308        state.covariancematrix[i1_p][i2_x] +=
309            strength * old_covar[i1_p][i1_p].sqrt() * old_covar[i2_x][i2_x].sqrt();
310        state.covariancematrix[i2_x][i1_p] +=
311            strength * old_covar[i1_p][i1_p].sqrt() * old_covar[i2_x][i2_x].sqrt();
312
313        Ok(())
314    }
315
316    /// Apply finite squeezing compensation
317    async fn apply_squeezing_compensation(
318        &mut self,
319        state: &mut GaussianState,
320    ) -> DeviceResult<()> {
321        println!("Applying finite squeezing compensation");
322
323        // For finite squeezing, we need to compensate for the fact that perfect
324        // cluster states require infinite squeezing. We apply additional local
325        // operations to improve the cluster state fidelity.
326
327        for mode in 0..self.config.num_modes {
328            // Calculate required compensation based on current variance
329            let var_x = state.covariancematrix[2 * mode][2 * mode];
330            let compensation_squeezing = if var_x > 0.1 {
331                -0.5 * var_x.ln() // Additional squeezing to reduce variance
332            } else {
333                0.0
334            };
335
336            if compensation_squeezing > 0.1 {
337                state.apply_squeezing(mode, compensation_squeezing, 0.0)?;
338            }
339        }
340
341        Ok(())
342    }
343
344    /// Calculate generation statistics
345    fn calculate_generation_statistics(&mut self, state: &GaussianState) {
346        // Calculate average entanglement
347        let entanglement_measures = state.calculate_entanglement_measures();
348        self.generation_stats.average_entanglement = entanglement_measures.logarithmic_negativity;
349
350        // Calculate nullifier violations (measure of finite squeezing effects)
351        let mut total_violation = 0.0;
352        for mode in 0..self.config.num_modes {
353            let var_x = state.covariancematrix[2 * mode][2 * mode];
354            // Ideal cluster state has zero x-variance
355            total_violation += var_x;
356        }
357        self.generation_stats.nullifier_violations = total_violation / self.config.num_modes as f64;
358
359        // Estimate generation fidelity
360        self.generation_stats.generation_fidelity = self.estimate_cluster_state_fidelity(state);
361    }
362
363    /// Estimate cluster state fidelity
364    fn estimate_cluster_state_fidelity(&self, state: &GaussianState) -> f64 {
365        // Simplified fidelity calculation based on nullifier violations
366        let ideal_variance = 0.0; // Perfect cluster state has zero x-variance
367        let actual_variance = self.generation_stats.nullifier_violations;
368
369        // Fidelity decreases with variance
370        let variance_penalty = (-actual_variance / 0.5).exp();
371
372        // Account for entanglement quality
373        let entanglement_bonus = (self.generation_stats.average_entanglement / 2.0).tanh();
374
375        (variance_penalty * (0.8 + 0.2 * entanglement_bonus)).clamp(0.0, 1.0)
376    }
377
378    /// Perform measurement-based computation on the cluster state
379    pub async fn perform_mbqc_sequence(
380        &mut self,
381        measurement_sequence: Vec<MBQCMeasurement>,
382    ) -> DeviceResult<Vec<MBQCResult>> {
383        if self.cluster_state.is_none() {
384            return Err(DeviceError::InvalidInput(
385                "No cluster state generated".to_string(),
386            ));
387        }
388
389        let mut state = self.cluster_state.as_ref().unwrap().clone();
390        let mut results = Vec::new();
391
392        println!(
393            "Performing MBQC sequence with {} measurements",
394            measurement_sequence.len()
395        );
396
397        for (i, measurement) in measurement_sequence.iter().enumerate() {
398            let result = self
399                .perform_single_mbqc_measurement(&mut state, measurement)
400                .await?;
401            results.push(result);
402
403            println!(
404                "Completed measurement {} of {}",
405                i + 1,
406                measurement_sequence.len()
407            );
408        }
409
410        Ok(results)
411    }
412
413    /// Perform a single MBQC measurement
414    async fn perform_single_mbqc_measurement(
415        &self,
416        state: &mut GaussianState,
417        measurement: &MBQCMeasurement,
418    ) -> DeviceResult<MBQCResult> {
419        match measurement.measurement_type {
420            MBQCMeasurementType::Homodyne { phase } => {
421                // Create a simplified measurement config
422                let config = CVDeviceConfig::default();
423                let measured_value =
424                    state.homodyne_measurement(measurement.mode, phase, &config)?;
425
426                Ok(MBQCResult {
427                    mode: measurement.mode,
428                    measurement_type: measurement.measurement_type.clone(),
429                    outcome: measured_value,
430                    feedforward_corrections: self
431                        .calculate_feedforward(measurement, measured_value),
432                    success_probability: 1.0, // Homodyne always succeeds
433                })
434            }
435
436            MBQCMeasurementType::Projection { target_value } => {
437                // Simplified projection measurement
438                let config = CVDeviceConfig::default();
439                let measured_value = state.homodyne_measurement(measurement.mode, 0.0, &config)?;
440                let success_prob =
441                    self.calculate_projection_success_probability(measured_value, target_value);
442
443                Ok(MBQCResult {
444                    mode: measurement.mode,
445                    measurement_type: measurement.measurement_type.clone(),
446                    outcome: measured_value,
447                    feedforward_corrections: Vec::new(),
448                    success_probability: success_prob,
449                })
450            }
451        }
452    }
453
454    /// Calculate feedforward corrections
455    fn calculate_feedforward(
456        &self,
457        measurement: &MBQCMeasurement,
458        outcome: f64,
459    ) -> Vec<FeedforwardCorrection> {
460        let mut corrections = Vec::new();
461
462        // Apply feedforward to neighboring modes
463        if let Some(neighbors) = self.config.graph_structure.get(&measurement.mode) {
464            for &neighbor in neighbors {
465                // Simplified feedforward: phase correction proportional to outcome
466                let correction_phase = outcome * 0.1; // Simplified calculation
467                corrections.push(FeedforwardCorrection {
468                    target_mode: neighbor,
469                    correction_type: CorrectionType::PhaseShift {
470                        phase: correction_phase,
471                    },
472                });
473            }
474        }
475
476        corrections
477    }
478
479    /// Calculate projection measurement success probability
480    fn calculate_projection_success_probability(&self, measured: f64, target: f64) -> f64 {
481        let tolerance = 0.5; // Tolerance for projection success
482        let deviation = (measured - target).abs();
483
484        if deviation <= tolerance {
485            1.0 - deviation / tolerance
486        } else {
487            0.0
488        }
489    }
490
491    /// Get current cluster state
492    pub fn get_cluster_state(&self) -> Option<&GaussianState> {
493        self.cluster_state.as_ref()
494    }
495
496    /// Get generation statistics
497    pub fn get_generation_statistics(&self) -> &GenerationStatistics {
498        &self.generation_stats
499    }
500
501    /// Validate cluster state properties
502    pub fn validate_cluster_state(&self) -> DeviceResult<ClusterStateValidation> {
503        if let Some(state) = &self.cluster_state {
504            let mut validation = ClusterStateValidation::default();
505
506            // Check nullifier properties
507            validation.nullifier_eigenvalues = self.calculate_nullifier_eigenvalues(state);
508            validation.max_nullifier_violation = validation
509                .nullifier_eigenvalues
510                .iter()
511                .fold(0.0, |acc, &x| acc.max(x));
512
513            // Check entanglement structure
514            validation.entanglement_spectrum = self.calculate_entanglement_spectrum(state);
515            validation.average_entanglement = validation.entanglement_spectrum.iter().sum::<f64>()
516                / validation.entanglement_spectrum.len() as f64;
517
518            // Overall validation
519            validation.is_valid =
520                validation.max_nullifier_violation < 0.1 && validation.average_entanglement > 0.5;
521
522            Ok(validation)
523        } else {
524            Err(DeviceError::InvalidInput(
525                "No cluster state to validate".to_string(),
526            ))
527        }
528    }
529
530    /// Calculate nullifier eigenvalues
531    fn calculate_nullifier_eigenvalues(&self, state: &GaussianState) -> Vec<f64> {
532        // Simplified calculation of nullifier operator eigenvalues
533        let mut eigenvalues = Vec::new();
534
535        for mode in 0..self.config.num_modes {
536            let var_x = state.covariancematrix[2 * mode][2 * mode];
537            eigenvalues.push(var_x);
538        }
539
540        eigenvalues
541    }
542
543    /// Calculate entanglement spectrum
544    fn calculate_entanglement_spectrum(&self, state: &GaussianState) -> Vec<f64> {
545        // Simplified entanglement spectrum calculation
546        let mut spectrum = Vec::new();
547
548        // Calculate bipartite entanglement for each possible bipartition
549        for i in 0..self.config.num_modes {
550            for j in (i + 1)..self.config.num_modes {
551                let cov_ij = state.covariancematrix[2 * i][2 * j];
552                let entanglement = cov_ij.abs(); // Simplified measure
553                spectrum.push(entanglement);
554            }
555        }
556
557        spectrum
558    }
559}
560
561/// MBQC measurement specification
562#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct MBQCMeasurement {
564    /// Mode to measure
565    pub mode: usize,
566    /// Type of measurement
567    pub measurement_type: MBQCMeasurementType,
568    /// Adaptive measurement (depends on previous results)
569    pub is_adaptive: bool,
570}
571
572/// Types of MBQC measurements
573#[derive(Debug, Clone, Serialize, Deserialize)]
574pub enum MBQCMeasurementType {
575    /// Homodyne measurement at specific phase
576    Homodyne { phase: f64 },
577    /// Projection onto specific value
578    Projection { target_value: f64 },
579}
580
581/// Result of an MBQC measurement
582#[derive(Debug, Clone, Serialize, Deserialize)]
583pub struct MBQCResult {
584    /// Measured mode
585    pub mode: usize,
586    /// Type of measurement performed
587    pub measurement_type: MBQCMeasurementType,
588    /// Measurement outcome
589    pub outcome: f64,
590    /// Required feedforward corrections
591    pub feedforward_corrections: Vec<FeedforwardCorrection>,
592    /// Success probability (for projection measurements)
593    pub success_probability: f64,
594}
595
596/// Feedforward correction specification
597#[derive(Debug, Clone, Serialize, Deserialize)]
598pub struct FeedforwardCorrection {
599    /// Target mode for correction
600    pub target_mode: usize,
601    /// Type of correction
602    pub correction_type: CorrectionType,
603}
604
605/// Types of feedforward corrections
606#[derive(Debug, Clone, Serialize, Deserialize)]
607pub enum CorrectionType {
608    /// Phase shift correction
609    PhaseShift { phase: f64 },
610    /// Displacement correction
611    Displacement { amplitude: Complex },
612    /// Squeezing correction
613    Squeezing { parameter: f64, phase: f64 },
614}
615
616/// Cluster state validation results
617#[derive(Debug, Clone, Serialize, Deserialize)]
618pub struct ClusterStateValidation {
619    /// Whether the cluster state is valid
620    pub is_valid: bool,
621    /// Nullifier operator eigenvalues
622    pub nullifier_eigenvalues: Vec<f64>,
623    /// Maximum nullifier violation
624    pub max_nullifier_violation: f64,
625    /// Entanglement spectrum
626    pub entanglement_spectrum: Vec<f64>,
627    /// Average entanglement
628    pub average_entanglement: f64,
629}
630
631impl Default for ClusterStateValidation {
632    fn default() -> Self {
633        Self {
634            is_valid: false,
635            nullifier_eigenvalues: Vec::new(),
636            max_nullifier_violation: 0.0,
637            entanglement_spectrum: Vec::new(),
638            average_entanglement: 0.0,
639        }
640    }
641}
642
643#[cfg(test)]
644mod tests {
645    use super::*;
646
647    #[test]
648    fn test_linear_cluster_config() {
649        let config = ClusterStateConfig::linear(5, 1.0);
650        assert_eq!(config.num_modes, 5);
651        assert_eq!(config.cluster_type, ClusterStateType::Linear);
652        assert_eq!(config.graph_structure.len(), 5);
653
654        // Check linear connectivity
655        assert_eq!(config.graph_structure[&0], vec![1]);
656        assert_eq!(config.graph_structure[&2], vec![1, 3]);
657        assert_eq!(config.graph_structure[&4], vec![3]);
658    }
659
660    #[test]
661    fn test_square_lattice_config() {
662        let config = ClusterStateConfig::square_lattice(3, 3, 1.0);
663        assert_eq!(config.num_modes, 9);
664        assert_eq!(config.cluster_type, ClusterStateType::Square);
665
666        // Check corner node (should have 2 neighbors)
667        assert_eq!(config.graph_structure[&0].len(), 2);
668        // Check center node (should have 4 neighbors)
669        assert_eq!(config.graph_structure[&4].len(), 4);
670    }
671
672    #[test]
673    fn test_custom_cluster_config() {
674        let adjacency = vec![
675            vec![false, true, false],
676            vec![true, false, true],
677            vec![false, true, false],
678        ];
679
680        let config = ClusterStateConfig::custom(adjacency, 1.0).unwrap();
681        assert_eq!(config.num_modes, 3);
682
683        // Check custom connectivity
684        assert_eq!(config.graph_structure[&0], vec![1]);
685        assert_eq!(config.graph_structure[&1], vec![0, 2]);
686        assert_eq!(config.graph_structure[&2], vec![1]);
687    }
688
689    #[tokio::test]
690    async fn test_cluster_state_generation() {
691        let config = ClusterStateConfig::linear(3, 1.0);
692        let mut generator = ClusterStateGenerator::new(config);
693
694        let state = generator.generate_cluster_state().await.unwrap();
695        assert_eq!(state.num_modes, 3);
696
697        let stats = generator.get_generation_statistics();
698        assert!(stats.total_entangling_gates > 0);
699        assert!(stats.generation_fidelity > 0.0);
700    }
701
702    #[tokio::test]
703    async fn test_mbqc_measurement() {
704        let config = ClusterStateConfig::linear(3, 1.0);
705        let mut generator = ClusterStateGenerator::new(config);
706        generator.generate_cluster_state().await.unwrap();
707
708        let measurements = vec![MBQCMeasurement {
709            mode: 0,
710            measurement_type: MBQCMeasurementType::Homodyne { phase: 0.0 },
711            is_adaptive: false,
712        }];
713
714        let results = generator.perform_mbqc_sequence(measurements).await.unwrap();
715        assert_eq!(results.len(), 1);
716        assert_eq!(results[0].success_probability, 1.0);
717    }
718
719    #[test]
720    fn test_cluster_validation() {
721        let config = ClusterStateConfig::linear(2, 1.0);
722        let generator = ClusterStateGenerator::new(config);
723
724        // Should fail validation without generated state
725        assert!(generator.validate_cluster_state().is_err());
726    }
727
728    #[test]
729    fn test_feedforward_calculation() {
730        let config = ClusterStateConfig::linear(3, 1.0);
731        let generator = ClusterStateGenerator::new(config);
732
733        let measurement = MBQCMeasurement {
734            mode: 1,
735            measurement_type: MBQCMeasurementType::Homodyne { phase: 0.0 },
736            is_adaptive: false,
737        };
738
739        let corrections = generator.calculate_feedforward(&measurement, 1.0);
740        assert_eq!(corrections.len(), 2); // Mode 1 has 2 neighbors in linear chain
741    }
742}