1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct QFTConfig {
21 pub spacetime_dimensions: usize,
23 pub lattice_size: Vec<usize>,
25 pub lattice_spacing: f64,
27 pub field_theory: FieldTheoryType,
29 pub boundary_conditions: QFTBoundaryConditions,
31 pub temperature: f64,
33 pub chemical_potential: f64,
35 pub coupling_constants: HashMap<String, f64>,
37 pub gauge_invariant: bool,
39 pub renormalization_scheme: RenormalizationScheme,
41 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum FieldTheoryType {
70 ScalarPhi4,
72 QED,
74 YangMills,
76 QCD,
78 ChiralFermions,
80 Higgs,
82 StandardModel,
84 NonLinearSigma,
86 GrossNeveu,
88 SineGordon,
90 Custom,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
96pub enum QFTBoundaryConditions {
97 Periodic,
99 Antiperiodic,
101 Open,
103 Twisted,
105 Mixed,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
111pub enum RenormalizationScheme {
112 DimensionalRegularization,
114 PauliVillars,
116 MomentumCutoff,
118 ZetaFunction,
120 MSBar,
122 OnShell,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
128pub enum FieldOperatorType {
129 Scalar,
131 Spinor,
133 Vector,
135 Tensor,
137 Creation,
139 Annihilation,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct FieldOperator {
146 pub field_type: FieldOperatorType,
148 pub position: Vec<f64>,
150 pub momentum: Option<Vec<f64>>,
152 pub component: usize,
154 pub time_ordering: TimeOrdering,
156 pub normal_ordering: bool,
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
162pub enum TimeOrdering {
163 TimeOrdered,
165 NormalOrdered,
167 AntiTimeOrdered,
169 Causal,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct PathIntegralConfig {
176 pub time_slices: usize,
178 pub time_step: f64,
180 pub action_type: ActionType,
182 pub mc_algorithm: MonteCarloAlgorithm,
184 pub importance_sampling: bool,
186 pub target_acceptance_rate: f64,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
192pub enum ActionType {
193 Euclidean,
195 Minkowski,
197 WickRotated,
199 Effective,
201 Wilson,
203 Improved,
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
209pub enum MonteCarloAlgorithm {
210 Metropolis,
212 Langevin,
214 HybridMonteCarlo,
216 Cluster,
218 Worm,
220 Multicanonical,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct GaugeFieldConfig {
227 pub gauge_group: GaugeGroup,
229 pub num_colors: usize,
231 pub gauge_coupling: f64,
233 pub gauge_fixing: GaugeFixing,
235 pub wilson_loops: Vec<WilsonLoop>,
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
241pub enum GaugeGroup {
242 U1,
244 SU(usize),
246 SO(usize),
248 Sp(usize),
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
254pub enum GaugeFixing {
255 Coulomb,
257 Landau,
259 Axial,
261 Temporal,
263 None,
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct WilsonLoop {
270 pub path: Vec<(usize, usize)>,
272 pub size: (usize, usize),
274 pub vev: Option<Complex64>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct RGFlow {
281 pub scale: f64,
283 pub beta_functions: HashMap<String, f64>,
285 pub anomalous_dimensions: HashMap<String, f64>,
287 pub running_couplings: HashMap<String, f64>,
289 pub fixed_points: Vec<FixedPoint>,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct FixedPoint {
296 pub couplings: HashMap<String, f64>,
298 pub eigenvalues: Vec<Complex64>,
300 pub fp_type: FixedPointType,
302}
303
304#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
306pub enum FixedPointType {
307 IRStable,
309 UVStable,
311 Saddle,
313 Gaussian,
315 Interacting,
317}
318
319#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct CorrelationFunction {
322 pub operators: Vec<FieldOperator>,
324 pub separations: Vec<Vec<f64>>,
326 pub values: Array1<Complex64>,
328 pub errors: Array1<f64>,
330 pub connected: bool,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct ScatteringProcess {
337 pub initial_state: Vec<ParticleState>,
339 pub final_state: Vec<ParticleState>,
341 pub cms_energy: f64,
343 pub scattering_angle: f64,
345 pub cross_section: Option<f64>,
347 pub s_matrix_element: Option<Complex64>,
349}
350
351#[derive(Debug, Clone, Serialize, Deserialize)]
353pub struct ParticleState {
354 pub particle_type: String,
356 pub momentum: [f64; 4],
358 pub spin_state: Vec<Complex64>,
360 pub quantum_numbers: HashMap<String, i32>,
362}
363
364#[derive(Debug)]
366pub struct QuantumFieldTheorySimulator {
367 config: QFTConfig,
369 field_configs: HashMap<String, Array4<Complex64>>,
371 gauge_configs: Option<GaugeFieldConfig>,
373 path_integral: Option<PathIntegralSampler>,
375 rg_flow: Option<RGFlow>,
377 correlations: HashMap<String, CorrelationFunction>,
379 backend: Option<SciRS2Backend>,
381 stats: QFTStats,
383}
384
385#[derive(Debug)]
387pub struct PathIntegralSampler {
388 config: PathIntegralConfig,
390 current_config: Array4<Complex64>,
392 action_evaluator: ActionEvaluator,
394 mc_state: MonteCarloState,
396 sample_history: VecDeque<Array4<Complex64>>,
398}
399
400#[derive(Debug)]
402pub struct ActionEvaluator {
403 theory_type: FieldTheoryType,
405 couplings: HashMap<String, f64>,
407 lattice_params: LatticeParameters,
409}
410
411#[derive(Debug, Clone, Serialize, Deserialize)]
413pub struct LatticeParameters {
414 pub spacing: f64,
416 pub bare_mass: f64,
418 pub hopping_parameter: f64,
420 pub plaquette_size: usize,
422}
423
424#[derive(Debug)]
426pub struct MonteCarloState {
427 pub step: usize,
429 pub acceptance_rate: f64,
431 pub accepted_moves: usize,
433 pub proposed_moves: usize,
435 pub current_action: f64,
437 pub autocorr_time: Option<f64>,
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
443pub struct QFTStats {
444 pub simulation_time: f64,
446 pub field_evaluations: usize,
448 pub pi_samples: usize,
450 pub correlation_calculations: usize,
452 pub rg_steps: usize,
454 pub avg_plaquette: Option<f64>,
456 pub topological_charge: Option<f64>,
458}
459
460impl QuantumFieldTheorySimulator {
461 pub fn new(config: QFTConfig) -> Result<Self> {
463 let mut field_configs = HashMap::new();
464
465 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 field_configs.insert("psi".to_string(), Array4::zeros(field_shape));
480 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 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 field_configs.insert(format!("A_{}_{}", mu, a), Array4::zeros(field_shape));
496 }
497 }
498
499 if config.field_theory == FieldTheoryType::QCD {
500 for flavor in 0..6 {
502 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 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 pub fn setup_gauge_fields(&mut self, gauge_config: GaugeFieldConfig) -> Result<()> {
581 let mut wilson_loops = Vec::new();
583
584 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 self.initialize_gauge_field_matrices(&gauge_conf)?;
600
601 self.gauge_configs = Some(gauge_conf);
602 Ok(())
603 }
604
605 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 let start_x = 0;
615 let start_t = 0;
616
617 for i in 0..spatial_size {
619 path.push((start_x + i, start_t));
620 }
621
622 for i in 0..temporal_size {
624 path.push((start_x + spatial_size - 1, start_t + i));
625 }
626
627 for i in 0..spatial_size {
629 path.push((start_x + spatial_size - 1 - i, start_t + temporal_size - 1));
630 }
631
632 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 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 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 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 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 let proposed_config = Self::propose_field_update(&pi_sampler.current_config)?;
699
700 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 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 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 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 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 self.stats.pi_samples += 1;
740 }
741
742 Ok(action_history)
743 }
744
745 fn propose_field_update(current_config: &Array4<Complex64>) -> Result<Array4<Complex64>> {
747 let mut proposed = current_config.clone();
748 let update_fraction = 0.1; 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 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 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 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 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 fn evaluate_correlator_on_config(
826 &self,
827 operators: &[FieldOperator],
828 separation: &[f64],
829 config: &Array4<Complex64>,
830 ) -> Result<Complex64> {
831 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 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 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 fn evaluate_wilson_loop(&self, wilson_loop: &WilsonLoop) -> Result<Complex64> {
889 let mut loop_value = Complex64::new(1.0, 0.0);
890
891 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 let mu = if next_site.0 != x { 0 } else { 3 }; 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 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 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 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 let dt = 0.01; 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 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 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 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 Ok(0.0)
977 }
978 _ => Ok(0.0),
979 }
980 }
981 FieldTheoryType::QED => {
982 match coupling_name {
983 "e" | "g" => {
984 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 let g = couplings.get("g").copied().unwrap_or(0.0);
1000 let n_colors = 3.0; 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 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 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)], fp_type: FixedPointType::Gaussian,
1028 });
1029
1030 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 fixed_points.push(FixedPoint {
1042 couplings: test_couplings,
1043 eigenvalues: vec![Complex64::new(1.0, 0.0)], fp_type: FixedPointType::Interacting,
1045 });
1046 }
1047 }
1048
1049 Ok(fixed_points)
1050 }
1051
1052 pub fn calculate_scattering_cross_section(
1054 &mut self,
1055 process: &ScatteringProcess,
1056 ) -> Result<f64> {
1057 let cms_energy = process.cms_energy;
1061 let num_initial = process.initial_state.len();
1062 let num_final = process.final_state.len();
1063
1064 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 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 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 pub fn get_statistics(&self) -> &QFTStats {
1100 &self.stats
1101 }
1102
1103 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 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 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 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 let mut laplacian = Complex64::new(0.0, 0.0);
1141
1142 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 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 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 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 let kinetic = -phi.conj() * laplacian;
1168
1169 let mass_term = mass_sq * phi.norm_sqr();
1171
1172 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 fn evaluate_qed_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1186 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 action += config.iter().map(|phi| phi.norm_sqr()).sum::<f64>() * lattice_spacing.powi(4);
1194
1195 Ok(action)
1196 }
1197
1198 fn evaluate_yang_mills_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1200 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); 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 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 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 let shape = config.shape();
1242
1243 let u_mu = config[[x, y, z, t]]; 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 ]]; 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 ]]; let u_nu = config[[x, y, z, t]]; let plaquette = u_mu * u_nu_shifted * u_mu_shifted.conj() * u_nu.conj();
1263
1264 Ok(plaquette)
1265 }
1266
1267 fn evaluate_generic_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1269 let lattice_spacing = self.lattice_params.spacing;
1270
1271 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 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); 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); }
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); }
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); }
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); }
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 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 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); 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 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}