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