quantrs2_sim/
quantum_field_theory.rs

1//! Quantum Field Theory Simulation Framework
2//!
3//! This module provides a comprehensive implementation of quantum field theory simulations,
4//! including field operators, path integrals, lattice gauge theories, renormalization
5//! group flows, and scattering process calculations. This framework enables simulation
6//! of relativistic quantum field dynamics and many-body quantum systems.
7
8use scirs2_core::ndarray::{Array1, Array4};
9use scirs2_core::random::{thread_rng, Rng};
10use scirs2_core::Complex64;
11use serde::{Deserialize, Serialize};
12use std::collections::{HashMap, VecDeque};
13use std::f64::consts::PI;
14
15use crate::error::{Result, SimulatorError};
16use crate::scirs2_integration::SciRS2Backend;
17use scirs2_core::random::prelude::*;
18
19/// Quantum field theory simulation configuration
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct QFTConfig {
22    /// Spacetime dimensions
23    pub spacetime_dimensions: usize,
24    /// Lattice size in each dimension
25    pub lattice_size: Vec<usize>,
26    /// Lattice spacing
27    pub lattice_spacing: f64,
28    /// Field theory type
29    pub field_theory: FieldTheoryType,
30    /// Boundary conditions
31    pub boundary_conditions: QFTBoundaryConditions,
32    /// Temperature for thermal field theory
33    pub temperature: f64,
34    /// Chemical potential
35    pub chemical_potential: f64,
36    /// Coupling constants
37    pub coupling_constants: HashMap<String, f64>,
38    /// Enable gauge invariance
39    pub gauge_invariant: bool,
40    /// Renormalization scheme
41    pub renormalization_scheme: RenormalizationScheme,
42    /// Path integral Monte Carlo steps
43    pub mc_steps: usize,
44}
45
46impl Default for QFTConfig {
47    fn default() -> Self {
48        let mut couplings = HashMap::new();
49        couplings.insert("g".to_string(), 0.1);
50        couplings.insert("lambda".to_string(), 0.01);
51
52        Self {
53            spacetime_dimensions: 4,
54            lattice_size: vec![16, 16, 16, 32],
55            lattice_spacing: 1.0,
56            field_theory: FieldTheoryType::ScalarPhi4,
57            boundary_conditions: QFTBoundaryConditions::Periodic,
58            temperature: 0.0,
59            chemical_potential: 0.0,
60            coupling_constants: couplings,
61            gauge_invariant: true,
62            renormalization_scheme: RenormalizationScheme::DimensionalRegularization,
63            mc_steps: 10_000,
64        }
65    }
66}
67
68/// Types of quantum field theories
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
70pub enum FieldTheoryType {
71    /// Scalar φ⁴ theory
72    ScalarPhi4,
73    /// Quantum Electrodynamics (QED)
74    QED,
75    /// Yang-Mills gauge theory
76    YangMills,
77    /// Quantum Chromodynamics (QCD)
78    QCD,
79    /// Chiral fermions
80    ChiralFermions,
81    /// Higgs field theory
82    Higgs,
83    /// Standard Model
84    StandardModel,
85    /// Non-linear sigma model
86    NonLinearSigma,
87    /// Gross-Neveu model
88    GrossNeveu,
89    /// Sine-Gordon model
90    SineGordon,
91    /// Custom field theory
92    Custom,
93}
94
95/// Boundary conditions for field theory
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
97pub enum QFTBoundaryConditions {
98    /// Periodic boundary conditions
99    Periodic,
100    /// Antiperiodic boundary conditions (for fermions)
101    Antiperiodic,
102    /// Open boundary conditions
103    Open,
104    /// Twisted boundary conditions
105    Twisted,
106    /// Mixed boundary conditions
107    Mixed,
108}
109
110/// Renormalization schemes
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
112pub enum RenormalizationScheme {
113    /// Dimensional regularization
114    DimensionalRegularization,
115    /// Pauli-Villars regularization
116    PauliVillars,
117    /// Momentum cutoff
118    MomentumCutoff,
119    /// Zeta function regularization
120    ZetaFunction,
121    /// MS-bar scheme
122    MSBar,
123    /// On-shell scheme
124    OnShell,
125}
126
127/// Field operator types
128#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
129pub enum FieldOperatorType {
130    /// Scalar field
131    Scalar,
132    /// Spinor field (fermion)
133    Spinor,
134    /// Vector field (gauge field)
135    Vector,
136    /// Tensor field
137    Tensor,
138    /// Creation operator
139    Creation,
140    /// Annihilation operator
141    Annihilation,
142}
143
144/// Quantum field operator
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct FieldOperator {
147    /// Field type
148    pub field_type: FieldOperatorType,
149    /// Spacetime position
150    pub position: Vec<f64>,
151    /// Momentum representation
152    pub momentum: Option<Vec<f64>>,
153    /// Field component index (for multi-component fields)
154    pub component: usize,
155    /// Time ordering
156    pub time_ordering: TimeOrdering,
157    /// Normal ordering coefficient
158    pub normal_ordering: bool,
159}
160
161/// Time ordering for field operators
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub enum TimeOrdering {
164    /// Time-ordered product
165    TimeOrdered,
166    /// Normal-ordered product
167    NormalOrdered,
168    /// Anti-time-ordered product
169    AntiTimeOrdered,
170    /// Causal ordering
171    Causal,
172}
173
174/// Path integral configuration
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct PathIntegralConfig {
177    /// Number of time slices
178    pub time_slices: usize,
179    /// Time step size
180    pub time_step: f64,
181    /// Action type
182    pub action_type: ActionType,
183    /// Monte Carlo algorithm
184    pub mc_algorithm: MonteCarloAlgorithm,
185    /// Importance sampling
186    pub importance_sampling: bool,
187    /// Metropolis acceptance rate target
188    pub target_acceptance_rate: f64,
189}
190
191/// Action types for path integrals
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
193pub enum ActionType {
194    /// Euclidean action
195    Euclidean,
196    /// Minkowski action
197    Minkowski,
198    /// Wick-rotated action
199    WickRotated,
200    /// Effective action
201    Effective,
202    /// Wilson action (lattice)
203    Wilson,
204    /// Improved action
205    Improved,
206}
207
208/// Monte Carlo algorithms for path integrals
209#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
210pub enum MonteCarloAlgorithm {
211    /// Metropolis-Hastings
212    Metropolis,
213    /// Langevin dynamics
214    Langevin,
215    /// Hybrid Monte Carlo
216    HybridMonteCarlo,
217    /// Cluster algorithms
218    Cluster,
219    /// Worm algorithms
220    Worm,
221    /// Multi-canonical sampling
222    Multicanonical,
223}
224
225/// Gauge field configuration
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct GaugeFieldConfig {
228    /// Gauge group (SU(N), U(1), etc.)
229    pub gauge_group: GaugeGroup,
230    /// Number of colors (for non-Abelian groups)
231    pub num_colors: usize,
232    /// Gauge coupling constant
233    pub gauge_coupling: f64,
234    /// Gauge fixing condition
235    pub gauge_fixing: GaugeFixing,
236    /// Wilson loop configurations
237    pub wilson_loops: Vec<WilsonLoop>,
238}
239
240/// Gauge groups
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
242pub enum GaugeGroup {
243    /// U(1) Abelian gauge group
244    U1,
245    /// SU(N) special unitary group
246    SU(usize),
247    /// SO(N) orthogonal group
248    SO(usize),
249    /// Sp(N) symplectic group
250    Sp(usize),
251}
252
253/// Gauge fixing conditions
254#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
255pub enum GaugeFixing {
256    /// Coulomb gauge
257    Coulomb,
258    /// Landau gauge
259    Landau,
260    /// Axial gauge
261    Axial,
262    /// Temporal gauge
263    Temporal,
264    /// No gauge fixing
265    None,
266}
267
268/// Wilson loop configuration
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct WilsonLoop {
271    /// Loop path on lattice
272    pub path: Vec<(usize, usize)>,
273    /// Loop size (spatial × temporal)
274    pub size: (usize, usize),
275    /// Expected vacuum expectation value
276    pub vev: Option<Complex64>,
277}
278
279/// Renormalization group flow data
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct RGFlow {
282    /// Energy scale
283    pub scale: f64,
284    /// Beta functions for coupling constants
285    pub beta_functions: HashMap<String, f64>,
286    /// Anomalous dimensions
287    pub anomalous_dimensions: HashMap<String, f64>,
288    /// Running coupling constants
289    pub running_couplings: HashMap<String, f64>,
290    /// Fixed points
291    pub fixed_points: Vec<FixedPoint>,
292}
293
294/// Fixed point in RG flow
295#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct FixedPoint {
297    /// Fixed point couplings
298    pub couplings: HashMap<String, f64>,
299    /// Stability (eigenvalues of linearized flow)
300    pub eigenvalues: Vec<Complex64>,
301    /// Fixed point type
302    pub fp_type: FixedPointType,
303}
304
305/// Types of RG fixed points
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
307pub enum FixedPointType {
308    /// Infrared stable (attractive)
309    IRStable,
310    /// Ultraviolet stable (repulsive)
311    UVStable,
312    /// Saddle point
313    Saddle,
314    /// Gaussian fixed point
315    Gaussian,
316    /// Non-trivial interacting fixed point
317    Interacting,
318}
319
320/// Correlation function data
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct CorrelationFunction {
323    /// Operator types
324    pub operators: Vec<FieldOperator>,
325    /// Spacetime separations
326    pub separations: Vec<Vec<f64>>,
327    /// Correlation values
328    pub values: Array1<Complex64>,
329    /// Statistical errors
330    pub errors: Array1<f64>,
331    /// Connected vs. disconnected parts
332    pub connected: bool,
333}
334
335/// Scattering process configuration
336#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct ScatteringProcess {
338    /// Initial state particles
339    pub initial_state: Vec<ParticleState>,
340    /// Final state particles
341    pub final_state: Vec<ParticleState>,
342    /// Center-of-mass energy
343    pub cms_energy: f64,
344    /// Scattering angle
345    pub scattering_angle: f64,
346    /// Cross section
347    pub cross_section: Option<f64>,
348    /// S-matrix element
349    pub s_matrix_element: Option<Complex64>,
350}
351
352/// Particle state in scattering
353#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct ParticleState {
355    /// Particle type/mass
356    pub particle_type: String,
357    /// Four-momentum
358    pub momentum: [f64; 4],
359    /// Spin/polarization state
360    pub spin_state: Vec<Complex64>,
361    /// Charge/quantum numbers
362    pub quantum_numbers: HashMap<String, i32>,
363}
364
365/// Main quantum field theory simulator
366#[derive(Debug)]
367pub struct QuantumFieldTheorySimulator {
368    /// Configuration
369    config: QFTConfig,
370    /// Field configurations on lattice
371    field_configs: HashMap<String, Array4<Complex64>>,
372    /// Gauge field configurations
373    gauge_configs: Option<GaugeFieldConfig>,
374    /// Path integral sampler
375    path_integral: Option<PathIntegralSampler>,
376    /// Renormalization group flow tracker
377    rg_flow: Option<RGFlow>,
378    /// Correlation function cache
379    correlations: HashMap<String, CorrelationFunction>,
380    /// `SciRS2` backend for numerical computations
381    backend: Option<SciRS2Backend>,
382    /// Simulation statistics
383    stats: QFTStats,
384}
385
386/// Path integral Monte Carlo sampler
387#[derive(Debug)]
388pub struct PathIntegralSampler {
389    /// Configuration
390    config: PathIntegralConfig,
391    /// Current field configuration
392    current_config: Array4<Complex64>,
393    /// Action evaluator
394    action_evaluator: ActionEvaluator,
395    /// Monte Carlo state
396    mc_state: MonteCarloState,
397    /// Sample history
398    sample_history: VecDeque<Array4<Complex64>>,
399}
400
401/// Action evaluator for different field theories
402#[derive(Debug)]
403pub struct ActionEvaluator {
404    /// Field theory type
405    theory_type: FieldTheoryType,
406    /// Coupling constants
407    couplings: HashMap<String, f64>,
408    /// Lattice parameters
409    lattice_params: LatticeParameters,
410}
411
412/// Lattice parameters
413#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct LatticeParameters {
415    /// Lattice spacing
416    pub spacing: f64,
417    /// Bare mass
418    pub bare_mass: f64,
419    /// Hopping parameter
420    pub hopping_parameter: f64,
421    /// Plaquette size
422    pub plaquette_size: usize,
423}
424
425/// Monte Carlo sampling state
426#[derive(Debug)]
427pub struct MonteCarloState {
428    /// Current step number
429    pub step: usize,
430    /// Acceptance rate
431    pub acceptance_rate: f64,
432    /// Total accepted moves
433    pub accepted_moves: usize,
434    /// Total proposed moves
435    pub proposed_moves: usize,
436    /// Current energy/action
437    pub current_action: f64,
438    /// Auto-correlation time
439    pub autocorr_time: Option<f64>,
440}
441
442/// QFT simulation statistics
443#[derive(Debug, Clone, Serialize, Deserialize)]
444pub struct QFTStats {
445    /// Total simulation time
446    pub simulation_time: f64,
447    /// Number of field evaluations
448    pub field_evaluations: usize,
449    /// Path integral samples
450    pub pi_samples: usize,
451    /// Correlation function calculations
452    pub correlation_calculations: usize,
453    /// RG flow steps
454    pub rg_steps: usize,
455    /// Average plaquette value
456    pub avg_plaquette: Option<f64>,
457    /// Topological charge
458    pub topological_charge: Option<f64>,
459}
460
461impl QuantumFieldTheorySimulator {
462    /// Create a new QFT simulator
463    pub fn new(config: QFTConfig) -> Result<Self> {
464        let mut field_configs = HashMap::new();
465
466        // Initialize field configurations based on theory type
467        let field_shape = (
468            config.lattice_size[0],
469            config.lattice_size[1],
470            config.lattice_size.get(2).copied().unwrap_or(1),
471            config.lattice_size.get(3).copied().unwrap_or(1),
472        );
473
474        match config.field_theory {
475            FieldTheoryType::ScalarPhi4 => {
476                field_configs.insert("phi".to_string(), Array4::zeros(field_shape));
477            }
478            FieldTheoryType::QED => {
479                // Fermion field
480                field_configs.insert("psi".to_string(), Array4::zeros(field_shape));
481                // Gauge field A_μ
482                for mu in 0..config.spacetime_dimensions {
483                    field_configs.insert(format!("A_{mu}"), Array4::zeros(field_shape));
484                }
485            }
486            FieldTheoryType::YangMills | FieldTheoryType::QCD => {
487                // Non-Abelian gauge fields
488                let num_colors: usize = match config.field_theory {
489                    FieldTheoryType::QCD => 3,
490                    _ => 2,
491                };
492
493                for mu in 0..config.spacetime_dimensions {
494                    for a in 0..num_colors.pow(2) - 1 {
495                        // SU(N) generators
496                        field_configs.insert(format!("A_{mu}_{a}"), Array4::zeros(field_shape));
497                    }
498                }
499
500                if config.field_theory == FieldTheoryType::QCD {
501                    // Quark fields
502                    for flavor in 0..6 {
503                        // 6 quark flavors
504                        field_configs.insert(format!("q_{flavor}"), Array4::zeros(field_shape));
505                    }
506                }
507            }
508            _ => {
509                field_configs.insert("default".to_string(), Array4::zeros(field_shape));
510            }
511        }
512
513        Ok(Self {
514            config,
515            field_configs,
516            gauge_configs: None,
517            path_integral: None,
518            rg_flow: None,
519            correlations: HashMap::new(),
520            backend: None,
521            stats: QFTStats::default(),
522        })
523    }
524
525    /// Initialize path integral sampler
526    pub fn initialize_path_integral(&mut self, pi_config: PathIntegralConfig) -> Result<()> {
527        let field_shape = (
528            self.config.lattice_size[0],
529            self.config.lattice_size[1],
530            self.config.lattice_size.get(2).copied().unwrap_or(1),
531            pi_config.time_slices,
532        );
533
534        let lattice_params = LatticeParameters {
535            spacing: self.config.lattice_spacing,
536            bare_mass: self
537                .config
538                .coupling_constants
539                .get("m0")
540                .copied()
541                .unwrap_or(1.0),
542            hopping_parameter: 1.0
543                / 2.0f64.mul_add(
544                    self.config
545                        .coupling_constants
546                        .get("m0")
547                        .copied()
548                        .unwrap_or(1.0),
549                    8.0,
550                ),
551            plaquette_size: 1,
552        };
553
554        let action_evaluator = ActionEvaluator {
555            theory_type: self.config.field_theory,
556            couplings: self.config.coupling_constants.clone(),
557            lattice_params,
558        };
559
560        let mc_state = MonteCarloState {
561            step: 0,
562            acceptance_rate: 0.0,
563            accepted_moves: 0,
564            proposed_moves: 0,
565            current_action: 0.0,
566            autocorr_time: None,
567        };
568
569        self.path_integral = Some(PathIntegralSampler {
570            config: pi_config,
571            current_config: Array4::zeros(field_shape),
572            action_evaluator,
573            mc_state,
574            sample_history: VecDeque::new(),
575        });
576
577        Ok(())
578    }
579
580    /// Set up gauge field configuration
581    pub fn setup_gauge_fields(&mut self, gauge_config: GaugeFieldConfig) -> Result<()> {
582        // Initialize Wilson loops for the gauge group
583        let mut wilson_loops = Vec::new();
584
585        // Create fundamental Wilson loops
586        for r in 1..=4 {
587            for t in 1..=4 {
588                wilson_loops.push(WilsonLoop {
589                    path: self.generate_wilson_loop_path(r, t)?,
590                    size: (r, t),
591                    vev: None,
592                });
593            }
594        }
595
596        let mut gauge_conf = gauge_config;
597        gauge_conf.wilson_loops = wilson_loops;
598
599        // Initialize gauge field matrices
600        self.initialize_gauge_field_matrices(&gauge_conf)?;
601
602        self.gauge_configs = Some(gauge_conf);
603        Ok(())
604    }
605
606    /// Generate Wilson loop path on lattice
607    fn generate_wilson_loop_path(
608        &self,
609        spatial_size: usize,
610        temporal_size: usize,
611    ) -> Result<Vec<(usize, usize)>> {
612        let mut path = Vec::new();
613
614        // Start at origin
615        let start_x = 0;
616        let start_t = 0;
617
618        // Go right (spatial direction) - spatial_size links
619        for i in 0..spatial_size {
620            path.push((start_x + i, start_t));
621        }
622
623        // Go up (temporal direction) - temporal_size links
624        for i in 0..temporal_size {
625            path.push((start_x + spatial_size - 1, start_t + i));
626        }
627
628        // Go left - spatial_size links
629        for i in 0..spatial_size {
630            path.push((start_x + spatial_size - 1 - i, start_t + temporal_size - 1));
631        }
632
633        // Go down - temporal_size links to close the loop
634        for i in 0..temporal_size {
635            path.push((start_x, start_t + temporal_size - 1 - i));
636        }
637
638        Ok(path)
639    }
640
641    /// Initialize gauge field matrices on lattice
642    fn initialize_gauge_field_matrices(&mut self, gauge_config: &GaugeFieldConfig) -> Result<()> {
643        let field_shape = (
644            self.config.lattice_size[0],
645            self.config.lattice_size[1],
646            self.config.lattice_size.get(2).copied().unwrap_or(1),
647            self.config.lattice_size.get(3).copied().unwrap_or(1),
648        );
649
650        match gauge_config.gauge_group {
651            GaugeGroup::U1 => {
652                // U(1) gauge field - single complex phase
653                for mu in 0..self.config.spacetime_dimensions {
654                    self.field_configs.insert(
655                        format!("U_{mu}"),
656                        Array4::from_elem(field_shape, Complex64::new(1.0, 0.0)),
657                    );
658                }
659            }
660            GaugeGroup::SU(n) => {
661                // SU(N) gauge field - N×N unitary matrices
662                for mu in 0..self.config.spacetime_dimensions {
663                    for i in 0..n {
664                        for j in 0..n {
665                            let initial_value = if i == j {
666                                Complex64::new(1.0, 0.0)
667                            } else {
668                                Complex64::new(0.0, 0.0)
669                            };
670
671                            self.field_configs.insert(
672                                format!("U_{mu}_{i}{j}"),
673                                Array4::from_elem(field_shape, initial_value),
674                            );
675                        }
676                    }
677                }
678            }
679            _ => {
680                return Err(SimulatorError::InvalidConfiguration(
681                    "Unsupported gauge group".to_string(),
682                ));
683            }
684        }
685
686        Ok(())
687    }
688
689    /// Run path integral Monte Carlo simulation
690    pub fn run_path_integral_mc(&mut self, num_steps: usize) -> Result<Vec<f64>> {
691        let pi_sampler = self.path_integral.as_mut().ok_or_else(|| {
692            SimulatorError::InvalidConfiguration("Path integral not initialized".to_string())
693        })?;
694
695        let mut action_history = Vec::with_capacity(num_steps);
696
697        for step in 0..num_steps {
698            // Propose field configuration update
699            let proposed_config = Self::propose_field_update(&pi_sampler.current_config)?;
700
701            // Calculate action difference
702            let current_action = pi_sampler
703                .action_evaluator
704                .evaluate_action(&pi_sampler.current_config)?;
705            let proposed_action = pi_sampler
706                .action_evaluator
707                .evaluate_action(&proposed_config)?;
708
709            let delta_action = proposed_action - current_action;
710
711            // Metropolis acceptance criterion
712            let accept_prob = (-delta_action).exp().min(1.0);
713            let rand_val: f64 = thread_rng().gen();
714
715            pi_sampler.mc_state.proposed_moves += 1;
716
717            if rand_val < accept_prob {
718                // Accept the move
719                pi_sampler.current_config = proposed_config;
720                pi_sampler.mc_state.current_action = proposed_action;
721                pi_sampler.mc_state.accepted_moves += 1;
722
723                // Store in history
724                if pi_sampler.sample_history.len() >= 1000 {
725                    pi_sampler.sample_history.pop_front();
726                }
727                pi_sampler
728                    .sample_history
729                    .push_back(pi_sampler.current_config.clone());
730            }
731
732            // Update acceptance rate
733            pi_sampler.mc_state.acceptance_rate = pi_sampler.mc_state.accepted_moves as f64
734                / pi_sampler.mc_state.proposed_moves as f64;
735
736            action_history.push(pi_sampler.mc_state.current_action);
737            pi_sampler.mc_state.step = step;
738
739            // Update statistics
740            self.stats.pi_samples += 1;
741        }
742
743        Ok(action_history)
744    }
745
746    /// Propose a field configuration update
747    fn propose_field_update(current_config: &Array4<Complex64>) -> Result<Array4<Complex64>> {
748        let mut proposed = current_config.clone();
749        let update_fraction = 0.1; // Update 10% of sites
750
751        let total_sites = proposed.len();
752        let sites_to_update = (total_sites as f64 * update_fraction) as usize;
753
754        let mut rng = thread_rng();
755        for _ in 0..sites_to_update {
756            let i = rng.gen_range(0..proposed.shape()[0]);
757            let j = rng.gen_range(0..proposed.shape()[1]);
758            let k = rng.gen_range(0..proposed.shape()[2]);
759            let l = rng.gen_range(0..proposed.shape()[3]);
760
761            // Gaussian random update
762            let delta_real: f64 = rng.gen::<f64>() - 0.5;
763            let delta_imag: f64 = rng.gen::<f64>() - 0.5;
764            let delta = Complex64::new(delta_real * 0.1, delta_imag * 0.1);
765
766            proposed[[i, j, k, l]] += delta;
767        }
768
769        Ok(proposed)
770    }
771
772    /// Calculate correlation functions
773    pub fn calculate_correlation_function(
774        &mut self,
775        operators: &[FieldOperator],
776        max_separation: usize,
777    ) -> Result<CorrelationFunction> {
778        let separations: Vec<Vec<f64>> = (0..=max_separation)
779            .map(|r| vec![r as f64, 0.0, 0.0, 0.0])
780            .collect();
781
782        let mut values = Array1::zeros(separations.len());
783        let mut errors = Array1::zeros(separations.len());
784
785        // Use path integral samples to calculate correlations
786        if let Some(pi_sampler) = &self.path_integral {
787            if !pi_sampler.sample_history.is_empty() {
788                for (sep_idx, separation) in separations.iter().enumerate() {
789                    let mut correlator_samples = Vec::new();
790
791                    for config in &pi_sampler.sample_history {
792                        let corr_value =
793                            self.evaluate_correlator_on_config(operators, separation, config)?;
794                        correlator_samples.push(corr_value);
795                    }
796
797                    // Calculate mean and standard error
798                    let mean = correlator_samples.iter().sum::<Complex64>()
799                        / correlator_samples.len() as f64;
800                    let variance = correlator_samples
801                        .iter()
802                        .map(|x| (x - mean).norm_sqr())
803                        .sum::<f64>()
804                        / correlator_samples.len() as f64;
805                    let std_error = (variance / correlator_samples.len() as f64).sqrt();
806
807                    values[sep_idx] = mean;
808                    errors[sep_idx] = std_error;
809                }
810            }
811        }
812
813        let correlation_fn = CorrelationFunction {
814            operators: operators.to_vec(),
815            separations,
816            values,
817            errors,
818            connected: true,
819        };
820
821        self.stats.correlation_calculations += 1;
822        Ok(correlation_fn)
823    }
824
825    /// Evaluate correlator on a specific field configuration
826    fn evaluate_correlator_on_config(
827        &self,
828        operators: &[FieldOperator],
829        separation: &[f64],
830        config: &Array4<Complex64>,
831    ) -> Result<Complex64> {
832        // For simplicity, calculate 2-point correlator ⟨φ(0)φ(r)⟩
833        if operators.len() != 2 {
834            return Err(SimulatorError::InvalidConfiguration(
835                "Only 2-point correlators currently supported".to_string(),
836            ));
837        }
838
839        let r = separation[0] as usize;
840        let lattice_size = config.shape()[0];
841
842        if r >= lattice_size {
843            return Ok(Complex64::new(0.0, 0.0));
844        }
845
846        let mut correlator = Complex64::new(0.0, 0.0);
847        let mut norm = 0.0;
848
849        // Average over all possible source positions
850        for x0 in 0..lattice_size {
851            for y0 in 0..config.shape()[1] {
852                for z0 in 0..config.shape()[2] {
853                    for t0 in 0..config.shape()[3] {
854                        let x1 = (x0 + r) % lattice_size;
855
856                        let field_0 = config[[x0, y0, z0, t0]];
857                        let field_r = config[[x1, y0, z0, t0]];
858
859                        correlator += field_0.conj() * field_r;
860                        norm += 1.0;
861                    }
862                }
863            }
864        }
865
866        Ok(correlator / norm)
867    }
868
869    /// Calculate Wilson loops for gauge theories
870    pub fn calculate_wilson_loops(&mut self) -> Result<HashMap<String, Complex64>> {
871        let gauge_config = self.gauge_configs.as_ref().ok_or_else(|| {
872            SimulatorError::InvalidConfiguration("Gauge fields not initialized".to_string())
873        })?;
874
875        let mut wilson_values = HashMap::new();
876
877        for (loop_idx, wilson_loop) in gauge_config.wilson_loops.iter().enumerate() {
878            let loop_value = self.evaluate_wilson_loop(wilson_loop)?;
879            wilson_values.insert(
880                format!("WL_{}x{}", wilson_loop.size.0, wilson_loop.size.1),
881                loop_value,
882            );
883        }
884
885        Ok(wilson_values)
886    }
887
888    /// Evaluate a single Wilson loop
889    fn evaluate_wilson_loop(&self, wilson_loop: &WilsonLoop) -> Result<Complex64> {
890        let mut loop_value = Complex64::new(1.0, 0.0);
891
892        // For U(1) gauge theory, Wilson loop is product of gauge links
893        for (i, &(x, t)) in wilson_loop.path.iter().enumerate() {
894            let next_site = wilson_loop.path.get(i + 1).unwrap_or(&wilson_loop.path[0]);
895
896            // Determine direction of link
897            let mu = if next_site.0 == x { 3 } else { 0 }; // spatial or temporal
898
899            if let Some(gauge_field) = self.field_configs.get(&format!("U_{mu}")) {
900                if x < gauge_field.shape()[0] && t < gauge_field.shape()[3] {
901                    let link_value = gauge_field[[x, 0, 0, t]];
902                    loop_value *= link_value;
903                }
904            }
905        }
906
907        Ok(loop_value)
908    }
909
910    /// Run renormalization group flow analysis
911    pub fn analyze_rg_flow(&mut self, energy_scales: &[f64]) -> Result<RGFlow> {
912        let mut beta_functions = HashMap::new();
913        let mut anomalous_dimensions = HashMap::new();
914        let mut running_couplings = HashMap::new();
915
916        // Initialize with bare couplings
917        for (coupling_name, &coupling_value) in &self.config.coupling_constants {
918            running_couplings.insert(coupling_name.clone(), coupling_value);
919        }
920
921        let mut rg_flow = RGFlow {
922            scale: energy_scales[0],
923            beta_functions,
924            anomalous_dimensions,
925            running_couplings: running_couplings.clone(),
926            fixed_points: Vec::new(),
927        };
928
929        // Calculate beta functions for each scale
930        for &scale in energy_scales {
931            let beta_g = self.calculate_beta_function("g", scale, &running_couplings)?;
932            let beta_lambda = self.calculate_beta_function("lambda", scale, &running_couplings)?;
933
934            rg_flow.beta_functions.insert("g".to_string(), beta_g);
935            rg_flow
936                .beta_functions
937                .insert("lambda".to_string(), beta_lambda);
938
939            // Update running couplings using RG equations
940            let dt = 0.01; // Small step in log(scale)
941            if let Some(g) = running_couplings.get_mut("g") {
942                *g += beta_g * dt;
943            }
944            if let Some(lambda) = running_couplings.get_mut("lambda") {
945                *lambda += beta_lambda * dt;
946            }
947
948            rg_flow.scale = scale;
949            rg_flow.running_couplings = running_couplings.clone();
950            self.stats.rg_steps += 1;
951        }
952
953        // Find fixed points
954        rg_flow.fixed_points = self.find_rg_fixed_points(&rg_flow.beta_functions)?;
955
956        self.rg_flow = Some(rg_flow.clone());
957        Ok(rg_flow)
958    }
959
960    /// Calculate beta function for a coupling
961    fn calculate_beta_function(
962        &self,
963        coupling_name: &str,
964        scale: f64,
965        couplings: &HashMap<String, f64>,
966    ) -> Result<f64> {
967        match self.config.field_theory {
968            FieldTheoryType::ScalarPhi4 => {
969                match coupling_name {
970                    "lambda" => {
971                        // β_λ = 3λ²/(4π)² in φ⁴ theory (one-loop)
972                        let lambda = couplings.get("lambda").copied().unwrap_or(0.0);
973                        Ok(3.0 * lambda.powi(2) / (16.0 * PI.powi(2)))
974                    }
975                    "g" => {
976                        // No gauge coupling in scalar theory
977                        Ok(0.0)
978                    }
979                    _ => Ok(0.0),
980                }
981            }
982            FieldTheoryType::QED => {
983                match coupling_name {
984                    "e" | "g" => {
985                        // β_e = e³/(12π²) in QED (one-loop)
986                        let e = couplings
987                            .get("e")
988                            .or_else(|| couplings.get("g"))
989                            .copied()
990                            .unwrap_or(0.0);
991                        Ok(e.powi(3) / (12.0 * PI.powi(2)))
992                    }
993                    _ => Ok(0.0),
994                }
995            }
996            FieldTheoryType::YangMills => {
997                match coupling_name {
998                    "g" => {
999                        // β_g = -b₀g³ where b₀ = 11N/(12π) for SU(N)
1000                        let g = couplings.get("g").copied().unwrap_or(0.0);
1001                        let n_colors = 3.0; // Default to SU(3)
1002                        let b0 = 11.0 * n_colors / (12.0 * PI);
1003                        Ok(-b0 * g.powi(3))
1004                    }
1005                    _ => Ok(0.0),
1006                }
1007            }
1008            _ => Ok(0.0),
1009        }
1010    }
1011
1012    /// Find fixed points in RG flow
1013    fn find_rg_fixed_points(
1014        &self,
1015        beta_functions: &HashMap<String, f64>,
1016    ) -> Result<Vec<FixedPoint>> {
1017        let mut fixed_points = Vec::new();
1018
1019        // Gaussian fixed point (all couplings = 0)
1020        let mut gaussian_couplings = HashMap::new();
1021        for coupling_name in beta_functions.keys() {
1022            gaussian_couplings.insert(coupling_name.clone(), 0.0);
1023        }
1024
1025        fixed_points.push(FixedPoint {
1026            couplings: gaussian_couplings,
1027            eigenvalues: vec![Complex64::new(-1.0, 0.0)], // IR attractive
1028            fp_type: FixedPointType::Gaussian,
1029        });
1030
1031        // Look for non-trivial fixed points numerically
1032        // (This is a simplified approach - real analysis would be more sophisticated)
1033        for lambda_star in [0.1, 0.5, 1.0, 2.0] {
1034            let mut test_couplings = HashMap::new();
1035            test_couplings.insert("lambda".to_string(), lambda_star);
1036            test_couplings.insert("g".to_string(), 0.0);
1037
1038            let beta_lambda = self.calculate_beta_function("lambda", 1.0, &test_couplings)?;
1039
1040            if beta_lambda.abs() < 1e-6 {
1041                // Found a fixed point
1042                fixed_points.push(FixedPoint {
1043                    couplings: test_couplings,
1044                    eigenvalues: vec![Complex64::new(1.0, 0.0)], // UV repulsive
1045                    fp_type: FixedPointType::Interacting,
1046                });
1047            }
1048        }
1049
1050        Ok(fixed_points)
1051    }
1052
1053    /// Calculate scattering cross section
1054    pub fn calculate_scattering_cross_section(
1055        &mut self,
1056        process: &ScatteringProcess,
1057    ) -> Result<f64> {
1058        // This is a simplified calculation - real implementation would involve
1059        // Feynman diagram evaluation, loop integrals, etc.
1060
1061        let cms_energy = process.cms_energy;
1062        let num_initial = process.initial_state.len();
1063        let num_final = process.final_state.len();
1064
1065        // Simple dimensional analysis estimate
1066        let coupling = self
1067            .config
1068            .coupling_constants
1069            .get("g")
1070            .copied()
1071            .unwrap_or(0.1);
1072
1073        let cross_section = match self.config.field_theory {
1074            FieldTheoryType::ScalarPhi4 => {
1075                // σ ~ λ²/s for 2→2 scattering
1076                if num_initial == 2 && num_final == 2 {
1077                    let lambda = self
1078                        .config
1079                        .coupling_constants
1080                        .get("lambda")
1081                        .copied()
1082                        .unwrap_or(0.01);
1083                    lambda.powi(2) / cms_energy.powi(2)
1084                } else {
1085                    0.0
1086                }
1087            }
1088            FieldTheoryType::QED => {
1089                // σ ~ α²/s for e⁺e⁻ → μ⁺μ⁻
1090                let alpha = coupling.powi(2) / (4.0 * PI);
1091                alpha.powi(2) / cms_energy.powi(2)
1092            }
1093            _ => coupling.powi(2) / cms_energy.powi(2),
1094        };
1095
1096        Ok(cross_section)
1097    }
1098
1099    /// Get simulation statistics
1100    #[must_use]
1101    pub const fn get_statistics(&self) -> &QFTStats {
1102        &self.stats
1103    }
1104
1105    /// Export field configurations for visualization
1106    pub fn export_field_configuration(&self, field_name: &str) -> Result<Array4<Complex64>> {
1107        self.field_configs.get(field_name).cloned().ok_or_else(|| {
1108            SimulatorError::InvalidConfiguration(format!("Field '{field_name}' not found"))
1109        })
1110    }
1111}
1112
1113impl ActionEvaluator {
1114    /// Evaluate the action for a given field configuration
1115    pub fn evaluate_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1116        match self.theory_type {
1117            FieldTheoryType::ScalarPhi4 => self.evaluate_phi4_action(config),
1118            FieldTheoryType::QED => self.evaluate_qed_action(config),
1119            FieldTheoryType::YangMills => self.evaluate_yang_mills_action(config),
1120            _ => self.evaluate_generic_action(config),
1121        }
1122    }
1123
1124    /// Evaluate φ⁴ scalar field theory action
1125    fn evaluate_phi4_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1126        let mut action = 0.0;
1127        let lattice_spacing = self.lattice_params.spacing;
1128        let mass_sq = self.lattice_params.bare_mass.powi(2);
1129        let lambda = self.couplings.get("lambda").copied().unwrap_or(0.01);
1130
1131        let shape = config.shape();
1132        let (nx, ny, nz, nt) = (shape[0], shape[1], shape[2], shape[3]);
1133
1134        // Kinetic term: -φ∇²φ
1135        for x in 0..nx {
1136            for y in 0..ny {
1137                for z in 0..nz {
1138                    for t in 0..nt {
1139                        let phi = config[[x, y, z, t]];
1140
1141                        // Laplacian in 4D
1142                        let mut laplacian = Complex64::new(0.0, 0.0);
1143
1144                        // x-direction
1145                        let phi_xp = config[[(x + 1) % nx, y, z, t]];
1146                        let phi_xm = config[[(x + nx - 1) % nx, y, z, t]];
1147                        laplacian += (phi_xp + phi_xm - 2.0 * phi) / lattice_spacing.powi(2);
1148
1149                        // y-direction
1150                        let phi_yp = config[[x, (y + 1) % ny, z, t]];
1151                        let phi_ym = config[[x, (y + ny - 1) % ny, z, t]];
1152                        laplacian += (phi_yp + phi_ym - 2.0 * phi) / lattice_spacing.powi(2);
1153
1154                        // z-direction if 3D
1155                        if nz > 1 {
1156                            let phi_zp = config[[x, y, (z + 1) % nz, t]];
1157                            let phi_zm = config[[x, y, (z + nz - 1) % nz, t]];
1158                            laplacian += (phi_zp + phi_zm - 2.0 * phi) / lattice_spacing.powi(2);
1159                        }
1160
1161                        // t-direction if 4D
1162                        if nt > 1 {
1163                            let phi_tp = config[[x, y, z, (t + 1) % nt]];
1164                            let phi_tm = config[[x, y, z, (t + nt - 1) % nt]];
1165                            laplacian += (phi_tp + phi_tm - 2.0 * phi) / lattice_spacing.powi(2);
1166                        }
1167
1168                        // Kinetic term
1169                        let kinetic = -phi.conj() * laplacian;
1170
1171                        // Mass term
1172                        let mass_term = mass_sq * phi.norm_sqr();
1173
1174                        // Interaction term φ⁴
1175                        let interaction = lambda * phi.norm_sqr().powi(2);
1176
1177                        action += (kinetic.re + mass_term + interaction) * lattice_spacing.powi(4);
1178                    }
1179                }
1180            }
1181        }
1182
1183        Ok(action)
1184    }
1185
1186    /// Evaluate QED action (simplified)
1187    fn evaluate_qed_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1188        // Simplified QED action evaluation
1189        let mut action = 0.0;
1190        let lattice_spacing = self.lattice_params.spacing;
1191        let e = self.couplings.get("e").copied().unwrap_or(0.1);
1192
1193        // This would normally involve gauge field kinetic terms,
1194        // fermion kinetic terms, and interaction terms
1195        action += config
1196            .iter()
1197            .map(scirs2_core::Complex::norm_sqr)
1198            .sum::<f64>()
1199            * lattice_spacing.powi(4);
1200
1201        Ok(action)
1202    }
1203
1204    /// Evaluate Yang-Mills action (simplified)
1205    fn evaluate_yang_mills_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1206        // Simplified Yang-Mills action with Wilson gauge action
1207        let mut action = 0.0;
1208        let lattice_spacing = self.lattice_params.spacing;
1209        let g = self.couplings.get("g").copied().unwrap_or(0.1);
1210        let beta = 2.0 / g.powi(2); // Lattice gauge theory beta parameter
1211
1212        // Wilson plaquette action: S = β Σ Re[Tr(1 - U_p)]
1213        let shape = config.shape();
1214        let (nx, ny, nz, nt) = (shape[0], shape[1], shape[2], shape[3]);
1215
1216        for x in 0..nx {
1217            for y in 0..ny {
1218                for z in 0..nz {
1219                    for t in 0..nt {
1220                        // Calculate plaquettes in all planes
1221                        let plaquette_xy = self.calculate_plaquette(config, x, y, z, t, 0, 1)?;
1222                        let plaquette_xt = self.calculate_plaquette(config, x, y, z, t, 0, 3)?;
1223                        let plaquette_yt = self.calculate_plaquette(config, x, y, z, t, 1, 3)?;
1224
1225                        action +=
1226                            beta * (3.0 - plaquette_xy.re - plaquette_xt.re - plaquette_yt.re);
1227                    }
1228                }
1229            }
1230        }
1231
1232        Ok(action)
1233    }
1234
1235    /// Calculate Wilson plaquette for Yang-Mills action
1236    fn calculate_plaquette(
1237        &self,
1238        config: &Array4<Complex64>,
1239        x: usize,
1240        y: usize,
1241        z: usize,
1242        t: usize,
1243        mu: usize,
1244        nu: usize,
1245    ) -> Result<Complex64> {
1246        // For simplicity, assume U(1) gauge theory where links are phases
1247        let shape = config.shape();
1248
1249        // Get gauge links around elementary plaquette
1250        let u_mu = config[[x, y, z, t]]; // U_μ(x)
1251        let u_nu_shifted = config[[
1252            (x + usize::from(mu == 0)) % shape[0],
1253            (y + usize::from(mu == 1)) % shape[1],
1254            z,
1255            t,
1256        ]]; // U_ν(x+μ)
1257
1258        let u_mu_shifted = config[[
1259            (x + usize::from(nu == 0)) % shape[0],
1260            (y + usize::from(nu == 1)) % shape[1],
1261            z,
1262            t,
1263        ]]; // U_μ(x+ν)
1264
1265        let u_nu = config[[x, y, z, t]]; // U_ν(x)
1266
1267        // Wilson plaquette: U_μ(x) U_ν(x+μ) U_μ†(x+ν) U_ν†(x)
1268        let plaquette = u_mu * u_nu_shifted * u_mu_shifted.conj() * u_nu.conj();
1269
1270        Ok(plaquette)
1271    }
1272
1273    /// Evaluate generic action for other field theories
1274    fn evaluate_generic_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1275        let lattice_spacing = self.lattice_params.spacing;
1276
1277        // Simple kinetic + mass action
1278        let action = config
1279            .iter()
1280            .map(scirs2_core::Complex::norm_sqr)
1281            .sum::<f64>()
1282            * lattice_spacing.powi(4);
1283
1284        Ok(action)
1285    }
1286}
1287
1288impl Default for QFTStats {
1289    fn default() -> Self {
1290        Self {
1291            simulation_time: 0.0,
1292            field_evaluations: 0,
1293            pi_samples: 0,
1294            correlation_calculations: 0,
1295            rg_steps: 0,
1296            avg_plaquette: None,
1297            topological_charge: None,
1298        }
1299    }
1300}
1301
1302#[cfg(test)]
1303mod tests {
1304    use super::*;
1305
1306    #[test]
1307    fn test_qft_simulator_creation() {
1308        let config = QFTConfig::default();
1309        let simulator = QuantumFieldTheorySimulator::new(config);
1310        assert!(simulator.is_ok());
1311    }
1312
1313    #[test]
1314    fn test_scalar_phi4_configuration() {
1315        let mut config = QFTConfig::default();
1316        config.field_theory = FieldTheoryType::ScalarPhi4;
1317        config.lattice_size = vec![8, 8, 8, 16];
1318
1319        let simulator = QuantumFieldTheorySimulator::new(config);
1320        assert!(simulator.is_ok());
1321
1322        let sim = simulator.expect("ScalarPhi4 simulator should be created successfully");
1323        assert!(sim.field_configs.contains_key("phi"));
1324    }
1325
1326    #[test]
1327    fn test_qed_configuration() {
1328        let mut config = QFTConfig::default();
1329        config.field_theory = FieldTheoryType::QED;
1330        config.spacetime_dimensions = 4;
1331
1332        let simulator = QuantumFieldTheorySimulator::new(config);
1333        assert!(simulator.is_ok());
1334
1335        let sim = simulator.expect("QED simulator should be created successfully");
1336        assert!(sim.field_configs.contains_key("psi"));
1337        assert!(sim.field_configs.contains_key("A_0"));
1338        assert!(sim.field_configs.contains_key("A_1"));
1339        assert!(sim.field_configs.contains_key("A_2"));
1340        assert!(sim.field_configs.contains_key("A_3"));
1341    }
1342
1343    #[test]
1344    fn test_path_integral_initialization() {
1345        let config = QFTConfig::default();
1346        let mut simulator = QuantumFieldTheorySimulator::new(config)
1347            .expect("QFT simulator should be created successfully");
1348
1349        let pi_config = PathIntegralConfig {
1350            time_slices: 32,
1351            time_step: 0.1,
1352            action_type: ActionType::Euclidean,
1353            mc_algorithm: MonteCarloAlgorithm::Metropolis,
1354            importance_sampling: true,
1355            target_acceptance_rate: 0.5,
1356        };
1357
1358        let result = simulator.initialize_path_integral(pi_config);
1359        assert!(result.is_ok());
1360        assert!(simulator.path_integral.is_some());
1361    }
1362
1363    #[test]
1364    fn test_gauge_field_setup_u1() {
1365        let config = QFTConfig::default();
1366        let mut simulator = QuantumFieldTheorySimulator::new(config)
1367            .expect("QFT simulator should be created successfully");
1368
1369        let gauge_config = GaugeFieldConfig {
1370            gauge_group: GaugeGroup::U1,
1371            num_colors: 1,
1372            gauge_coupling: 0.1,
1373            gauge_fixing: GaugeFixing::Landau,
1374            wilson_loops: Vec::new(),
1375        };
1376
1377        let result = simulator.setup_gauge_fields(gauge_config);
1378        assert!(result.is_ok());
1379        assert!(simulator.gauge_configs.is_some());
1380    }
1381
1382    #[test]
1383    fn test_gauge_field_setup_su3() {
1384        let config = QFTConfig::default();
1385        let mut simulator = QuantumFieldTheorySimulator::new(config)
1386            .expect("QFT simulator should be created successfully");
1387
1388        let gauge_config = GaugeFieldConfig {
1389            gauge_group: GaugeGroup::SU(3),
1390            num_colors: 3,
1391            gauge_coupling: 0.2,
1392            gauge_fixing: GaugeFixing::Coulomb,
1393            wilson_loops: Vec::new(),
1394        };
1395
1396        let result = simulator.setup_gauge_fields(gauge_config);
1397        assert!(result.is_ok());
1398        assert!(simulator.gauge_configs.is_some());
1399
1400        // Check that SU(3) gauge field matrices are created
1401        assert!(simulator.field_configs.contains_key("U_0_00"));
1402        assert!(simulator.field_configs.contains_key("U_0_11"));
1403        assert!(simulator.field_configs.contains_key("U_0_22"));
1404    }
1405
1406    #[test]
1407    fn test_wilson_loop_generation() {
1408        let config = QFTConfig::default();
1409        let simulator = QuantumFieldTheorySimulator::new(config)
1410            .expect("QFT simulator should be created successfully");
1411
1412        let path = simulator
1413            .generate_wilson_loop_path(2, 3)
1414            .expect("Wilson loop path generation should succeed");
1415        assert_eq!(path.len(), 10); // 2+3+2+3 = 10 links for rectangular loop
1416
1417        // Check that path forms a closed loop
1418        assert_eq!(path[0], path[path.len() - 1]);
1419    }
1420
1421    #[test]
1422    fn test_action_evaluation_phi4() {
1423        let config = QFTConfig::default();
1424        let _simulator = QuantumFieldTheorySimulator::new(config)
1425            .expect("QFT simulator should be created successfully");
1426
1427        let lattice_params = LatticeParameters {
1428            spacing: 1.0,
1429            bare_mass: 1.0,
1430            hopping_parameter: 0.125,
1431            plaquette_size: 1,
1432        };
1433
1434        let mut couplings = HashMap::new();
1435        couplings.insert("lambda".to_string(), 0.1);
1436
1437        let evaluator = ActionEvaluator {
1438            theory_type: FieldTheoryType::ScalarPhi4,
1439            couplings,
1440            lattice_params,
1441        };
1442
1443        let field_config = Array4::zeros((4, 4, 4, 4));
1444        let action = evaluator.evaluate_action(&field_config);
1445        assert!(action.is_ok());
1446        assert_eq!(
1447            action.expect("Action evaluation should succeed for zero field"),
1448            0.0
1449        ); // Zero field gives zero action
1450    }
1451
1452    #[test]
1453    fn test_beta_function_phi4() {
1454        let config = QFTConfig::default();
1455        let simulator = QuantumFieldTheorySimulator::new(config)
1456            .expect("QFT simulator should be created successfully");
1457
1458        let mut couplings = HashMap::new();
1459        couplings.insert("lambda".to_string(), 0.1);
1460
1461        let beta_lambda = simulator.calculate_beta_function("lambda", 1.0, &couplings);
1462        assert!(beta_lambda.is_ok());
1463
1464        let beta_val = beta_lambda.expect("Beta function calculation should succeed");
1465        assert!(beta_val > 0.0); // Positive beta function in phi^4 theory
1466    }
1467
1468    #[test]
1469    fn test_beta_function_qed() {
1470        let mut config = QFTConfig::default();
1471        config.field_theory = FieldTheoryType::QED;
1472        let simulator = QuantumFieldTheorySimulator::new(config)
1473            .expect("QED simulator should be created successfully");
1474
1475        let mut couplings = HashMap::new();
1476        couplings.insert("e".to_string(), 0.3);
1477
1478        let beta_e = simulator.calculate_beta_function("e", 1.0, &couplings);
1479        assert!(beta_e.is_ok());
1480
1481        let beta_val = beta_e.expect("QED beta function calculation should succeed");
1482        assert!(beta_val > 0.0); // QED has positive beta function (Landau pole)
1483    }
1484
1485    #[test]
1486    fn test_beta_function_yang_mills() {
1487        let mut config = QFTConfig::default();
1488        config.field_theory = FieldTheoryType::YangMills;
1489        let simulator = QuantumFieldTheorySimulator::new(config)
1490            .expect("Yang-Mills simulator should be created successfully");
1491
1492        let mut couplings = HashMap::new();
1493        couplings.insert("g".to_string(), 0.5);
1494
1495        let beta_g = simulator.calculate_beta_function("g", 1.0, &couplings);
1496        assert!(beta_g.is_ok());
1497
1498        let beta_val = beta_g.expect("Yang-Mills beta function calculation should succeed");
1499        assert!(beta_val < 0.0); // Yang-Mills has negative beta function (asymptotic freedom)
1500    }
1501
1502    #[test]
1503    fn test_rg_flow_analysis() {
1504        let config = QFTConfig::default();
1505        let mut simulator = QuantumFieldTheorySimulator::new(config)
1506            .expect("QFT simulator should be created successfully");
1507
1508        let energy_scales = [0.1, 1.0, 10.0, 100.0];
1509        let rg_flow = simulator.analyze_rg_flow(&energy_scales);
1510        assert!(rg_flow.is_ok());
1511
1512        let flow = rg_flow.expect("RG flow analysis should succeed");
1513        assert!(flow.beta_functions.contains_key("lambda"));
1514        assert!(!flow.fixed_points.is_empty());
1515        assert!(flow
1516            .fixed_points
1517            .iter()
1518            .any(|fp| fp.fp_type == FixedPointType::Gaussian));
1519    }
1520
1521    #[test]
1522    fn test_scattering_cross_section_phi4() {
1523        let config = QFTConfig::default();
1524        let mut simulator = QuantumFieldTheorySimulator::new(config)
1525            .expect("QFT simulator should be created successfully");
1526
1527        let process = ScatteringProcess {
1528            initial_state: vec![
1529                ParticleState {
1530                    particle_type: "phi".to_string(),
1531                    momentum: [1.0, 0.0, 0.0, 0.0],
1532                    spin_state: vec![Complex64::new(1.0, 0.0)],
1533                    quantum_numbers: HashMap::new(),
1534                },
1535                ParticleState {
1536                    particle_type: "phi".to_string(),
1537                    momentum: [-1.0, 0.0, 0.0, 0.0],
1538                    spin_state: vec![Complex64::new(1.0, 0.0)],
1539                    quantum_numbers: HashMap::new(),
1540                },
1541            ],
1542            final_state: vec![
1543                ParticleState {
1544                    particle_type: "phi".to_string(),
1545                    momentum: [0.0, 1.0, 0.0, 0.0],
1546                    spin_state: vec![Complex64::new(1.0, 0.0)],
1547                    quantum_numbers: HashMap::new(),
1548                },
1549                ParticleState {
1550                    particle_type: "phi".to_string(),
1551                    momentum: [0.0, -1.0, 0.0, 0.0],
1552                    spin_state: vec![Complex64::new(1.0, 0.0)],
1553                    quantum_numbers: HashMap::new(),
1554                },
1555            ],
1556            cms_energy: 2.0,
1557            scattering_angle: PI / 2.0,
1558            cross_section: None,
1559            s_matrix_element: None,
1560        };
1561
1562        let cross_section = simulator.calculate_scattering_cross_section(&process);
1563        assert!(cross_section.is_ok());
1564
1565        let sigma = cross_section.expect("Cross section calculation should succeed");
1566        assert!(sigma > 0.0);
1567        assert!(sigma.is_finite());
1568    }
1569
1570    #[test]
1571    fn test_field_operator_creation() {
1572        let field_op = FieldOperator {
1573            field_type: FieldOperatorType::Scalar,
1574            position: vec![0.0, 0.0, 0.0, 0.0],
1575            momentum: None,
1576            component: 0,
1577            time_ordering: TimeOrdering::TimeOrdered,
1578            normal_ordering: true,
1579        };
1580
1581        assert_eq!(field_op.field_type, FieldOperatorType::Scalar);
1582        assert_eq!(field_op.position.len(), 4);
1583        assert!(field_op.normal_ordering);
1584    }
1585
1586    #[test]
1587    #[ignore]
1588    fn test_path_integral_monte_carlo_short() {
1589        let config = QFTConfig::default();
1590        let mut simulator = QuantumFieldTheorySimulator::new(config)
1591            .expect("QFT simulator should be created successfully");
1592
1593        let pi_config = PathIntegralConfig {
1594            time_slices: 8,
1595            time_step: 0.1,
1596            action_type: ActionType::Euclidean,
1597            mc_algorithm: MonteCarloAlgorithm::Metropolis,
1598            importance_sampling: true,
1599            target_acceptance_rate: 0.5,
1600        };
1601
1602        simulator
1603            .initialize_path_integral(pi_config)
1604            .expect("Path integral initialization should succeed");
1605
1606        // Run short Monte Carlo simulation
1607        let result = simulator.run_path_integral_mc(100);
1608        assert!(result.is_ok());
1609
1610        let action_history = result.expect("Path integral MC should complete successfully");
1611        assert_eq!(action_history.len(), 100);
1612        assert!(action_history.iter().all(|&a| a.is_finite()));
1613    }
1614
1615    #[test]
1616    #[ignore]
1617    fn test_correlation_function_calculation() {
1618        let config = QFTConfig::default();
1619        let mut simulator = QuantumFieldTheorySimulator::new(config)
1620            .expect("QFT simulator should be created successfully");
1621
1622        let pi_config = PathIntegralConfig {
1623            time_slices: 8,
1624            time_step: 0.1,
1625            action_type: ActionType::Euclidean,
1626            mc_algorithm: MonteCarloAlgorithm::Metropolis,
1627            importance_sampling: true,
1628            target_acceptance_rate: 0.5,
1629        };
1630
1631        simulator
1632            .initialize_path_integral(pi_config)
1633            .expect("Path integral initialization should succeed");
1634
1635        // Generate some samples first
1636        simulator
1637            .run_path_integral_mc(50)
1638            .expect("Path integral MC should complete successfully");
1639
1640        let operators = vec![
1641            FieldOperator {
1642                field_type: FieldOperatorType::Scalar,
1643                position: vec![0.0, 0.0, 0.0, 0.0],
1644                momentum: None,
1645                component: 0,
1646                time_ordering: TimeOrdering::TimeOrdered,
1647                normal_ordering: true,
1648            },
1649            FieldOperator {
1650                field_type: FieldOperatorType::Scalar,
1651                position: vec![1.0, 0.0, 0.0, 0.0],
1652                momentum: None,
1653                component: 0,
1654                time_ordering: TimeOrdering::TimeOrdered,
1655                normal_ordering: true,
1656            },
1657        ];
1658
1659        let correlation = simulator.calculate_correlation_function(&operators, 4);
1660        assert!(correlation.is_ok());
1661
1662        let corr_fn = correlation.expect("Correlation function calculation should succeed");
1663        assert_eq!(corr_fn.separations.len(), 5); // 0, 1, 2, 3, 4
1664        assert_eq!(corr_fn.values.len(), 5);
1665        assert_eq!(corr_fn.errors.len(), 5);
1666    }
1667
1668    #[test]
1669    fn test_export_field_configuration() {
1670        let config = QFTConfig::default();
1671        let simulator = QuantumFieldTheorySimulator::new(config)
1672            .expect("QFT simulator should be created successfully");
1673
1674        let field_config = simulator.export_field_configuration("phi");
1675        assert!(field_config.is_ok());
1676
1677        let config_array = field_config.expect("Field configuration export should succeed");
1678        assert_eq!(config_array.ndim(), 4);
1679
1680        // Test non-existent field
1681        let invalid_field = simulator.export_field_configuration("nonexistent");
1682        assert!(invalid_field.is_err());
1683    }
1684
1685    #[test]
1686    fn test_statistics_tracking() {
1687        let config = QFTConfig::default();
1688        let simulator = QuantumFieldTheorySimulator::new(config)
1689            .expect("QFT simulator should be created successfully");
1690
1691        let stats = simulator.get_statistics();
1692        assert_eq!(stats.field_evaluations, 0);
1693        assert_eq!(stats.pi_samples, 0);
1694        assert_eq!(stats.correlation_calculations, 0);
1695        assert_eq!(stats.rg_steps, 0);
1696    }
1697}