1use scirs2_core::ndarray::{Array1, Array4};
9use scirs2_core::random::{thread_rng, Rng};
10use scirs2_core::Complex64;
11use serde::{Deserialize, Serialize};
12use std::collections::{HashMap, VecDeque};
13use std::f64::consts::PI;
14
15use crate::error::{Result, SimulatorError};
16use crate::scirs2_integration::SciRS2Backend;
17use scirs2_core::random::prelude::*;
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct QFTConfig {
22 pub spacetime_dimensions: usize,
24 pub lattice_size: Vec<usize>,
26 pub lattice_spacing: f64,
28 pub field_theory: FieldTheoryType,
30 pub boundary_conditions: QFTBoundaryConditions,
32 pub temperature: f64,
34 pub chemical_potential: f64,
36 pub coupling_constants: HashMap<String, f64>,
38 pub gauge_invariant: bool,
40 pub renormalization_scheme: RenormalizationScheme,
42 pub mc_steps: usize,
44}
45
46impl Default for QFTConfig {
47 fn default() -> Self {
48 let mut couplings = HashMap::new();
49 couplings.insert("g".to_string(), 0.1);
50 couplings.insert("lambda".to_string(), 0.01);
51
52 Self {
53 spacetime_dimensions: 4,
54 lattice_size: vec![16, 16, 16, 32],
55 lattice_spacing: 1.0,
56 field_theory: FieldTheoryType::ScalarPhi4,
57 boundary_conditions: QFTBoundaryConditions::Periodic,
58 temperature: 0.0,
59 chemical_potential: 0.0,
60 coupling_constants: couplings,
61 gauge_invariant: true,
62 renormalization_scheme: RenormalizationScheme::DimensionalRegularization,
63 mc_steps: 10_000,
64 }
65 }
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
70pub enum FieldTheoryType {
71 ScalarPhi4,
73 QED,
75 YangMills,
77 QCD,
79 ChiralFermions,
81 Higgs,
83 StandardModel,
85 NonLinearSigma,
87 GrossNeveu,
89 SineGordon,
91 Custom,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
97pub enum QFTBoundaryConditions {
98 Periodic,
100 Antiperiodic,
102 Open,
104 Twisted,
106 Mixed,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
112pub enum RenormalizationScheme {
113 DimensionalRegularization,
115 PauliVillars,
117 MomentumCutoff,
119 ZetaFunction,
121 MSBar,
123 OnShell,
125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
129pub enum FieldOperatorType {
130 Scalar,
132 Spinor,
134 Vector,
136 Tensor,
138 Creation,
140 Annihilation,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct FieldOperator {
147 pub field_type: FieldOperatorType,
149 pub position: Vec<f64>,
151 pub momentum: Option<Vec<f64>>,
153 pub component: usize,
155 pub time_ordering: TimeOrdering,
157 pub normal_ordering: bool,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
163pub enum TimeOrdering {
164 TimeOrdered,
166 NormalOrdered,
168 AntiTimeOrdered,
170 Causal,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct PathIntegralConfig {
177 pub time_slices: usize,
179 pub time_step: f64,
181 pub action_type: ActionType,
183 pub mc_algorithm: MonteCarloAlgorithm,
185 pub importance_sampling: bool,
187 pub target_acceptance_rate: f64,
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
193pub enum ActionType {
194 Euclidean,
196 Minkowski,
198 WickRotated,
200 Effective,
202 Wilson,
204 Improved,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
210pub enum MonteCarloAlgorithm {
211 Metropolis,
213 Langevin,
215 HybridMonteCarlo,
217 Cluster,
219 Worm,
221 Multicanonical,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct GaugeFieldConfig {
228 pub gauge_group: GaugeGroup,
230 pub num_colors: usize,
232 pub gauge_coupling: f64,
234 pub gauge_fixing: GaugeFixing,
236 pub wilson_loops: Vec<WilsonLoop>,
238}
239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
242pub enum GaugeGroup {
243 U1,
245 SU(usize),
247 SO(usize),
249 Sp(usize),
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
255pub enum GaugeFixing {
256 Coulomb,
258 Landau,
260 Axial,
262 Temporal,
264 None,
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct WilsonLoop {
271 pub path: Vec<(usize, usize)>,
273 pub size: (usize, usize),
275 pub vev: Option<Complex64>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct RGFlow {
282 pub scale: f64,
284 pub beta_functions: HashMap<String, f64>,
286 pub anomalous_dimensions: HashMap<String, f64>,
288 pub running_couplings: HashMap<String, f64>,
290 pub fixed_points: Vec<FixedPoint>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296pub struct FixedPoint {
297 pub couplings: HashMap<String, f64>,
299 pub eigenvalues: Vec<Complex64>,
301 pub fp_type: FixedPointType,
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
307pub enum FixedPointType {
308 IRStable,
310 UVStable,
312 Saddle,
314 Gaussian,
316 Interacting,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct CorrelationFunction {
323 pub operators: Vec<FieldOperator>,
325 pub separations: Vec<Vec<f64>>,
327 pub values: Array1<Complex64>,
329 pub errors: Array1<f64>,
331 pub connected: bool,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct ScatteringProcess {
338 pub initial_state: Vec<ParticleState>,
340 pub final_state: Vec<ParticleState>,
342 pub cms_energy: f64,
344 pub scattering_angle: f64,
346 pub cross_section: Option<f64>,
348 pub s_matrix_element: Option<Complex64>,
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct ParticleState {
355 pub particle_type: String,
357 pub momentum: [f64; 4],
359 pub spin_state: Vec<Complex64>,
361 pub quantum_numbers: HashMap<String, i32>,
363}
364
365#[derive(Debug)]
367pub struct QuantumFieldTheorySimulator {
368 config: QFTConfig,
370 field_configs: HashMap<String, Array4<Complex64>>,
372 gauge_configs: Option<GaugeFieldConfig>,
374 path_integral: Option<PathIntegralSampler>,
376 rg_flow: Option<RGFlow>,
378 correlations: HashMap<String, CorrelationFunction>,
380 backend: Option<SciRS2Backend>,
382 stats: QFTStats,
384}
385
386#[derive(Debug)]
388pub struct PathIntegralSampler {
389 config: PathIntegralConfig,
391 current_config: Array4<Complex64>,
393 action_evaluator: ActionEvaluator,
395 mc_state: MonteCarloState,
397 sample_history: VecDeque<Array4<Complex64>>,
399}
400
401#[derive(Debug)]
403pub struct ActionEvaluator {
404 theory_type: FieldTheoryType,
406 couplings: HashMap<String, f64>,
408 lattice_params: LatticeParameters,
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize)]
414pub struct LatticeParameters {
415 pub spacing: f64,
417 pub bare_mass: f64,
419 pub hopping_parameter: f64,
421 pub plaquette_size: usize,
423}
424
425#[derive(Debug)]
427pub struct MonteCarloState {
428 pub step: usize,
430 pub acceptance_rate: f64,
432 pub accepted_moves: usize,
434 pub proposed_moves: usize,
436 pub current_action: f64,
438 pub autocorr_time: Option<f64>,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize)]
444pub struct QFTStats {
445 pub simulation_time: f64,
447 pub field_evaluations: usize,
449 pub pi_samples: usize,
451 pub correlation_calculations: usize,
453 pub rg_steps: usize,
455 pub avg_plaquette: Option<f64>,
457 pub topological_charge: Option<f64>,
459}
460
461impl QuantumFieldTheorySimulator {
462 pub fn new(config: QFTConfig) -> Result<Self> {
464 let mut field_configs = HashMap::new();
465
466 let field_shape = (
468 config.lattice_size[0],
469 config.lattice_size[1],
470 config.lattice_size.get(2).copied().unwrap_or(1),
471 config.lattice_size.get(3).copied().unwrap_or(1),
472 );
473
474 match config.field_theory {
475 FieldTheoryType::ScalarPhi4 => {
476 field_configs.insert("phi".to_string(), Array4::zeros(field_shape));
477 }
478 FieldTheoryType::QED => {
479 field_configs.insert("psi".to_string(), Array4::zeros(field_shape));
481 for mu in 0..config.spacetime_dimensions {
483 field_configs.insert(format!("A_{mu}"), Array4::zeros(field_shape));
484 }
485 }
486 FieldTheoryType::YangMills | FieldTheoryType::QCD => {
487 let num_colors: usize = match config.field_theory {
489 FieldTheoryType::QCD => 3,
490 _ => 2,
491 };
492
493 for mu in 0..config.spacetime_dimensions {
494 for a in 0..num_colors.pow(2) - 1 {
495 field_configs.insert(format!("A_{mu}_{a}"), Array4::zeros(field_shape));
497 }
498 }
499
500 if config.field_theory == FieldTheoryType::QCD {
501 for flavor in 0..6 {
503 field_configs.insert(format!("q_{flavor}"), Array4::zeros(field_shape));
505 }
506 }
507 }
508 _ => {
509 field_configs.insert("default".to_string(), Array4::zeros(field_shape));
510 }
511 }
512
513 Ok(Self {
514 config,
515 field_configs,
516 gauge_configs: None,
517 path_integral: None,
518 rg_flow: None,
519 correlations: HashMap::new(),
520 backend: None,
521 stats: QFTStats::default(),
522 })
523 }
524
525 pub fn initialize_path_integral(&mut self, pi_config: PathIntegralConfig) -> Result<()> {
527 let field_shape = (
528 self.config.lattice_size[0],
529 self.config.lattice_size[1],
530 self.config.lattice_size.get(2).copied().unwrap_or(1),
531 pi_config.time_slices,
532 );
533
534 let lattice_params = LatticeParameters {
535 spacing: self.config.lattice_spacing,
536 bare_mass: self
537 .config
538 .coupling_constants
539 .get("m0")
540 .copied()
541 .unwrap_or(1.0),
542 hopping_parameter: 1.0
543 / 2.0f64.mul_add(
544 self.config
545 .coupling_constants
546 .get("m0")
547 .copied()
548 .unwrap_or(1.0),
549 8.0,
550 ),
551 plaquette_size: 1,
552 };
553
554 let action_evaluator = ActionEvaluator {
555 theory_type: self.config.field_theory,
556 couplings: self.config.coupling_constants.clone(),
557 lattice_params,
558 };
559
560 let mc_state = MonteCarloState {
561 step: 0,
562 acceptance_rate: 0.0,
563 accepted_moves: 0,
564 proposed_moves: 0,
565 current_action: 0.0,
566 autocorr_time: None,
567 };
568
569 self.path_integral = Some(PathIntegralSampler {
570 config: pi_config,
571 current_config: Array4::zeros(field_shape),
572 action_evaluator,
573 mc_state,
574 sample_history: VecDeque::new(),
575 });
576
577 Ok(())
578 }
579
580 pub fn setup_gauge_fields(&mut self, gauge_config: GaugeFieldConfig) -> Result<()> {
582 let mut wilson_loops = Vec::new();
584
585 for r in 1..=4 {
587 for t in 1..=4 {
588 wilson_loops.push(WilsonLoop {
589 path: self.generate_wilson_loop_path(r, t)?,
590 size: (r, t),
591 vev: None,
592 });
593 }
594 }
595
596 let mut gauge_conf = gauge_config;
597 gauge_conf.wilson_loops = wilson_loops;
598
599 self.initialize_gauge_field_matrices(&gauge_conf)?;
601
602 self.gauge_configs = Some(gauge_conf);
603 Ok(())
604 }
605
606 fn generate_wilson_loop_path(
608 &self,
609 spatial_size: usize,
610 temporal_size: usize,
611 ) -> Result<Vec<(usize, usize)>> {
612 let mut path = Vec::new();
613
614 let start_x = 0;
616 let start_t = 0;
617
618 for i in 0..spatial_size {
620 path.push((start_x + i, start_t));
621 }
622
623 for i in 0..temporal_size {
625 path.push((start_x + spatial_size - 1, start_t + i));
626 }
627
628 for i in 0..spatial_size {
630 path.push((start_x + spatial_size - 1 - i, start_t + temporal_size - 1));
631 }
632
633 for i in 0..temporal_size {
635 path.push((start_x, start_t + temporal_size - 1 - i));
636 }
637
638 Ok(path)
639 }
640
641 fn initialize_gauge_field_matrices(&mut self, gauge_config: &GaugeFieldConfig) -> Result<()> {
643 let field_shape = (
644 self.config.lattice_size[0],
645 self.config.lattice_size[1],
646 self.config.lattice_size.get(2).copied().unwrap_or(1),
647 self.config.lattice_size.get(3).copied().unwrap_or(1),
648 );
649
650 match gauge_config.gauge_group {
651 GaugeGroup::U1 => {
652 for mu in 0..self.config.spacetime_dimensions {
654 self.field_configs.insert(
655 format!("U_{mu}"),
656 Array4::from_elem(field_shape, Complex64::new(1.0, 0.0)),
657 );
658 }
659 }
660 GaugeGroup::SU(n) => {
661 for mu in 0..self.config.spacetime_dimensions {
663 for i in 0..n {
664 for j in 0..n {
665 let initial_value = if i == j {
666 Complex64::new(1.0, 0.0)
667 } else {
668 Complex64::new(0.0, 0.0)
669 };
670
671 self.field_configs.insert(
672 format!("U_{mu}_{i}{j}"),
673 Array4::from_elem(field_shape, initial_value),
674 );
675 }
676 }
677 }
678 }
679 _ => {
680 return Err(SimulatorError::InvalidConfiguration(
681 "Unsupported gauge group".to_string(),
682 ));
683 }
684 }
685
686 Ok(())
687 }
688
689 pub fn run_path_integral_mc(&mut self, num_steps: usize) -> Result<Vec<f64>> {
691 let pi_sampler = self.path_integral.as_mut().ok_or_else(|| {
692 SimulatorError::InvalidConfiguration("Path integral not initialized".to_string())
693 })?;
694
695 let mut action_history = Vec::with_capacity(num_steps);
696
697 for step in 0..num_steps {
698 let proposed_config = Self::propose_field_update(&pi_sampler.current_config)?;
700
701 let current_action = pi_sampler
703 .action_evaluator
704 .evaluate_action(&pi_sampler.current_config)?;
705 let proposed_action = pi_sampler
706 .action_evaluator
707 .evaluate_action(&proposed_config)?;
708
709 let delta_action = proposed_action - current_action;
710
711 let accept_prob = (-delta_action).exp().min(1.0);
713 let rand_val: f64 = thread_rng().gen();
714
715 pi_sampler.mc_state.proposed_moves += 1;
716
717 if rand_val < accept_prob {
718 pi_sampler.current_config = proposed_config;
720 pi_sampler.mc_state.current_action = proposed_action;
721 pi_sampler.mc_state.accepted_moves += 1;
722
723 if pi_sampler.sample_history.len() >= 1000 {
725 pi_sampler.sample_history.pop_front();
726 }
727 pi_sampler
728 .sample_history
729 .push_back(pi_sampler.current_config.clone());
730 }
731
732 pi_sampler.mc_state.acceptance_rate = pi_sampler.mc_state.accepted_moves as f64
734 / pi_sampler.mc_state.proposed_moves as f64;
735
736 action_history.push(pi_sampler.mc_state.current_action);
737 pi_sampler.mc_state.step = step;
738
739 self.stats.pi_samples += 1;
741 }
742
743 Ok(action_history)
744 }
745
746 fn propose_field_update(current_config: &Array4<Complex64>) -> Result<Array4<Complex64>> {
748 let mut proposed = current_config.clone();
749 let update_fraction = 0.1; let total_sites = proposed.len();
752 let sites_to_update = (total_sites as f64 * update_fraction) as usize;
753
754 let mut rng = thread_rng();
755 for _ in 0..sites_to_update {
756 let i = rng.gen_range(0..proposed.shape()[0]);
757 let j = rng.gen_range(0..proposed.shape()[1]);
758 let k = rng.gen_range(0..proposed.shape()[2]);
759 let l = rng.gen_range(0..proposed.shape()[3]);
760
761 let delta_real: f64 = rng.gen::<f64>() - 0.5;
763 let delta_imag: f64 = rng.gen::<f64>() - 0.5;
764 let delta = Complex64::new(delta_real * 0.1, delta_imag * 0.1);
765
766 proposed[[i, j, k, l]] += delta;
767 }
768
769 Ok(proposed)
770 }
771
772 pub fn calculate_correlation_function(
774 &mut self,
775 operators: &[FieldOperator],
776 max_separation: usize,
777 ) -> Result<CorrelationFunction> {
778 let separations: Vec<Vec<f64>> = (0..=max_separation)
779 .map(|r| vec![r as f64, 0.0, 0.0, 0.0])
780 .collect();
781
782 let mut values = Array1::zeros(separations.len());
783 let mut errors = Array1::zeros(separations.len());
784
785 if let Some(pi_sampler) = &self.path_integral {
787 if !pi_sampler.sample_history.is_empty() {
788 for (sep_idx, separation) in separations.iter().enumerate() {
789 let mut correlator_samples = Vec::new();
790
791 for config in &pi_sampler.sample_history {
792 let corr_value =
793 self.evaluate_correlator_on_config(operators, separation, config)?;
794 correlator_samples.push(corr_value);
795 }
796
797 let mean = correlator_samples.iter().sum::<Complex64>()
799 / correlator_samples.len() as f64;
800 let variance = correlator_samples
801 .iter()
802 .map(|x| (x - mean).norm_sqr())
803 .sum::<f64>()
804 / correlator_samples.len() as f64;
805 let std_error = (variance / correlator_samples.len() as f64).sqrt();
806
807 values[sep_idx] = mean;
808 errors[sep_idx] = std_error;
809 }
810 }
811 }
812
813 let correlation_fn = CorrelationFunction {
814 operators: operators.to_vec(),
815 separations,
816 values,
817 errors,
818 connected: true,
819 };
820
821 self.stats.correlation_calculations += 1;
822 Ok(correlation_fn)
823 }
824
825 fn evaluate_correlator_on_config(
827 &self,
828 operators: &[FieldOperator],
829 separation: &[f64],
830 config: &Array4<Complex64>,
831 ) -> Result<Complex64> {
832 if operators.len() != 2 {
834 return Err(SimulatorError::InvalidConfiguration(
835 "Only 2-point correlators currently supported".to_string(),
836 ));
837 }
838
839 let r = separation[0] as usize;
840 let lattice_size = config.shape()[0];
841
842 if r >= lattice_size {
843 return Ok(Complex64::new(0.0, 0.0));
844 }
845
846 let mut correlator = Complex64::new(0.0, 0.0);
847 let mut norm = 0.0;
848
849 for x0 in 0..lattice_size {
851 for y0 in 0..config.shape()[1] {
852 for z0 in 0..config.shape()[2] {
853 for t0 in 0..config.shape()[3] {
854 let x1 = (x0 + r) % lattice_size;
855
856 let field_0 = config[[x0, y0, z0, t0]];
857 let field_r = config[[x1, y0, z0, t0]];
858
859 correlator += field_0.conj() * field_r;
860 norm += 1.0;
861 }
862 }
863 }
864 }
865
866 Ok(correlator / norm)
867 }
868
869 pub fn calculate_wilson_loops(&mut self) -> Result<HashMap<String, Complex64>> {
871 let gauge_config = self.gauge_configs.as_ref().ok_or_else(|| {
872 SimulatorError::InvalidConfiguration("Gauge fields not initialized".to_string())
873 })?;
874
875 let mut wilson_values = HashMap::new();
876
877 for (loop_idx, wilson_loop) in gauge_config.wilson_loops.iter().enumerate() {
878 let loop_value = self.evaluate_wilson_loop(wilson_loop)?;
879 wilson_values.insert(
880 format!("WL_{}x{}", wilson_loop.size.0, wilson_loop.size.1),
881 loop_value,
882 );
883 }
884
885 Ok(wilson_values)
886 }
887
888 fn evaluate_wilson_loop(&self, wilson_loop: &WilsonLoop) -> Result<Complex64> {
890 let mut loop_value = Complex64::new(1.0, 0.0);
891
892 for (i, &(x, t)) in wilson_loop.path.iter().enumerate() {
894 let next_site = wilson_loop.path.get(i + 1).unwrap_or(&wilson_loop.path[0]);
895
896 let mu = if next_site.0 == x { 3 } else { 0 }; if let Some(gauge_field) = self.field_configs.get(&format!("U_{mu}")) {
900 if x < gauge_field.shape()[0] && t < gauge_field.shape()[3] {
901 let link_value = gauge_field[[x, 0, 0, t]];
902 loop_value *= link_value;
903 }
904 }
905 }
906
907 Ok(loop_value)
908 }
909
910 pub fn analyze_rg_flow(&mut self, energy_scales: &[f64]) -> Result<RGFlow> {
912 let mut beta_functions = HashMap::new();
913 let mut anomalous_dimensions = HashMap::new();
914 let mut running_couplings = HashMap::new();
915
916 for (coupling_name, &coupling_value) in &self.config.coupling_constants {
918 running_couplings.insert(coupling_name.clone(), coupling_value);
919 }
920
921 let mut rg_flow = RGFlow {
922 scale: energy_scales[0],
923 beta_functions,
924 anomalous_dimensions,
925 running_couplings: running_couplings.clone(),
926 fixed_points: Vec::new(),
927 };
928
929 for &scale in energy_scales {
931 let beta_g = self.calculate_beta_function("g", scale, &running_couplings)?;
932 let beta_lambda = self.calculate_beta_function("lambda", scale, &running_couplings)?;
933
934 rg_flow.beta_functions.insert("g".to_string(), beta_g);
935 rg_flow
936 .beta_functions
937 .insert("lambda".to_string(), beta_lambda);
938
939 let dt = 0.01; if let Some(g) = running_couplings.get_mut("g") {
942 *g += beta_g * dt;
943 }
944 if let Some(lambda) = running_couplings.get_mut("lambda") {
945 *lambda += beta_lambda * dt;
946 }
947
948 rg_flow.scale = scale;
949 rg_flow.running_couplings = running_couplings.clone();
950 self.stats.rg_steps += 1;
951 }
952
953 rg_flow.fixed_points = self.find_rg_fixed_points(&rg_flow.beta_functions)?;
955
956 self.rg_flow = Some(rg_flow.clone());
957 Ok(rg_flow)
958 }
959
960 fn calculate_beta_function(
962 &self,
963 coupling_name: &str,
964 scale: f64,
965 couplings: &HashMap<String, f64>,
966 ) -> Result<f64> {
967 match self.config.field_theory {
968 FieldTheoryType::ScalarPhi4 => {
969 match coupling_name {
970 "lambda" => {
971 let lambda = couplings.get("lambda").copied().unwrap_or(0.0);
973 Ok(3.0 * lambda.powi(2) / (16.0 * PI.powi(2)))
974 }
975 "g" => {
976 Ok(0.0)
978 }
979 _ => Ok(0.0),
980 }
981 }
982 FieldTheoryType::QED => {
983 match coupling_name {
984 "e" | "g" => {
985 let e = couplings
987 .get("e")
988 .or_else(|| couplings.get("g"))
989 .copied()
990 .unwrap_or(0.0);
991 Ok(e.powi(3) / (12.0 * PI.powi(2)))
992 }
993 _ => Ok(0.0),
994 }
995 }
996 FieldTheoryType::YangMills => {
997 match coupling_name {
998 "g" => {
999 let g = couplings.get("g").copied().unwrap_or(0.0);
1001 let n_colors = 3.0; let b0 = 11.0 * n_colors / (12.0 * PI);
1003 Ok(-b0 * g.powi(3))
1004 }
1005 _ => Ok(0.0),
1006 }
1007 }
1008 _ => Ok(0.0),
1009 }
1010 }
1011
1012 fn find_rg_fixed_points(
1014 &self,
1015 beta_functions: &HashMap<String, f64>,
1016 ) -> Result<Vec<FixedPoint>> {
1017 let mut fixed_points = Vec::new();
1018
1019 let mut gaussian_couplings = HashMap::new();
1021 for coupling_name in beta_functions.keys() {
1022 gaussian_couplings.insert(coupling_name.clone(), 0.0);
1023 }
1024
1025 fixed_points.push(FixedPoint {
1026 couplings: gaussian_couplings,
1027 eigenvalues: vec![Complex64::new(-1.0, 0.0)], fp_type: FixedPointType::Gaussian,
1029 });
1030
1031 for lambda_star in [0.1, 0.5, 1.0, 2.0] {
1034 let mut test_couplings = HashMap::new();
1035 test_couplings.insert("lambda".to_string(), lambda_star);
1036 test_couplings.insert("g".to_string(), 0.0);
1037
1038 let beta_lambda = self.calculate_beta_function("lambda", 1.0, &test_couplings)?;
1039
1040 if beta_lambda.abs() < 1e-6 {
1041 fixed_points.push(FixedPoint {
1043 couplings: test_couplings,
1044 eigenvalues: vec![Complex64::new(1.0, 0.0)], fp_type: FixedPointType::Interacting,
1046 });
1047 }
1048 }
1049
1050 Ok(fixed_points)
1051 }
1052
1053 pub fn calculate_scattering_cross_section(
1055 &mut self,
1056 process: &ScatteringProcess,
1057 ) -> Result<f64> {
1058 let cms_energy = process.cms_energy;
1062 let num_initial = process.initial_state.len();
1063 let num_final = process.final_state.len();
1064
1065 let coupling = self
1067 .config
1068 .coupling_constants
1069 .get("g")
1070 .copied()
1071 .unwrap_or(0.1);
1072
1073 let cross_section = match self.config.field_theory {
1074 FieldTheoryType::ScalarPhi4 => {
1075 if num_initial == 2 && num_final == 2 {
1077 let lambda = self
1078 .config
1079 .coupling_constants
1080 .get("lambda")
1081 .copied()
1082 .unwrap_or(0.01);
1083 lambda.powi(2) / cms_energy.powi(2)
1084 } else {
1085 0.0
1086 }
1087 }
1088 FieldTheoryType::QED => {
1089 let alpha = coupling.powi(2) / (4.0 * PI);
1091 alpha.powi(2) / cms_energy.powi(2)
1092 }
1093 _ => coupling.powi(2) / cms_energy.powi(2),
1094 };
1095
1096 Ok(cross_section)
1097 }
1098
1099 #[must_use]
1101 pub const fn get_statistics(&self) -> &QFTStats {
1102 &self.stats
1103 }
1104
1105 pub fn export_field_configuration(&self, field_name: &str) -> Result<Array4<Complex64>> {
1107 self.field_configs.get(field_name).cloned().ok_or_else(|| {
1108 SimulatorError::InvalidConfiguration(format!("Field '{field_name}' not found"))
1109 })
1110 }
1111}
1112
1113impl ActionEvaluator {
1114 pub fn evaluate_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1116 match self.theory_type {
1117 FieldTheoryType::ScalarPhi4 => self.evaluate_phi4_action(config),
1118 FieldTheoryType::QED => self.evaluate_qed_action(config),
1119 FieldTheoryType::YangMills => self.evaluate_yang_mills_action(config),
1120 _ => self.evaluate_generic_action(config),
1121 }
1122 }
1123
1124 fn evaluate_phi4_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1126 let mut action = 0.0;
1127 let lattice_spacing = self.lattice_params.spacing;
1128 let mass_sq = self.lattice_params.bare_mass.powi(2);
1129 let lambda = self.couplings.get("lambda").copied().unwrap_or(0.01);
1130
1131 let shape = config.shape();
1132 let (nx, ny, nz, nt) = (shape[0], shape[1], shape[2], shape[3]);
1133
1134 for x in 0..nx {
1136 for y in 0..ny {
1137 for z in 0..nz {
1138 for t in 0..nt {
1139 let phi = config[[x, y, z, t]];
1140
1141 let mut laplacian = Complex64::new(0.0, 0.0);
1143
1144 let phi_xp = config[[(x + 1) % nx, y, z, t]];
1146 let phi_xm = config[[(x + nx - 1) % nx, y, z, t]];
1147 laplacian += (phi_xp + phi_xm - 2.0 * phi) / lattice_spacing.powi(2);
1148
1149 let phi_yp = config[[x, (y + 1) % ny, z, t]];
1151 let phi_ym = config[[x, (y + ny - 1) % ny, z, t]];
1152 laplacian += (phi_yp + phi_ym - 2.0 * phi) / lattice_spacing.powi(2);
1153
1154 if nz > 1 {
1156 let phi_zp = config[[x, y, (z + 1) % nz, t]];
1157 let phi_zm = config[[x, y, (z + nz - 1) % nz, t]];
1158 laplacian += (phi_zp + phi_zm - 2.0 * phi) / lattice_spacing.powi(2);
1159 }
1160
1161 if nt > 1 {
1163 let phi_tp = config[[x, y, z, (t + 1) % nt]];
1164 let phi_tm = config[[x, y, z, (t + nt - 1) % nt]];
1165 laplacian += (phi_tp + phi_tm - 2.0 * phi) / lattice_spacing.powi(2);
1166 }
1167
1168 let kinetic = -phi.conj() * laplacian;
1170
1171 let mass_term = mass_sq * phi.norm_sqr();
1173
1174 let interaction = lambda * phi.norm_sqr().powi(2);
1176
1177 action += (kinetic.re + mass_term + interaction) * lattice_spacing.powi(4);
1178 }
1179 }
1180 }
1181 }
1182
1183 Ok(action)
1184 }
1185
1186 fn evaluate_qed_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1188 let mut action = 0.0;
1190 let lattice_spacing = self.lattice_params.spacing;
1191 let e = self.couplings.get("e").copied().unwrap_or(0.1);
1192
1193 action += config
1196 .iter()
1197 .map(scirs2_core::Complex::norm_sqr)
1198 .sum::<f64>()
1199 * lattice_spacing.powi(4);
1200
1201 Ok(action)
1202 }
1203
1204 fn evaluate_yang_mills_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1206 let mut action = 0.0;
1208 let lattice_spacing = self.lattice_params.spacing;
1209 let g = self.couplings.get("g").copied().unwrap_or(0.1);
1210 let beta = 2.0 / g.powi(2); let shape = config.shape();
1214 let (nx, ny, nz, nt) = (shape[0], shape[1], shape[2], shape[3]);
1215
1216 for x in 0..nx {
1217 for y in 0..ny {
1218 for z in 0..nz {
1219 for t in 0..nt {
1220 let plaquette_xy = self.calculate_plaquette(config, x, y, z, t, 0, 1)?;
1222 let plaquette_xt = self.calculate_plaquette(config, x, y, z, t, 0, 3)?;
1223 let plaquette_yt = self.calculate_plaquette(config, x, y, z, t, 1, 3)?;
1224
1225 action +=
1226 beta * (3.0 - plaquette_xy.re - plaquette_xt.re - plaquette_yt.re);
1227 }
1228 }
1229 }
1230 }
1231
1232 Ok(action)
1233 }
1234
1235 fn calculate_plaquette(
1237 &self,
1238 config: &Array4<Complex64>,
1239 x: usize,
1240 y: usize,
1241 z: usize,
1242 t: usize,
1243 mu: usize,
1244 nu: usize,
1245 ) -> Result<Complex64> {
1246 let shape = config.shape();
1248
1249 let u_mu = config[[x, y, z, t]]; let u_nu_shifted = config[[
1252 (x + usize::from(mu == 0)) % shape[0],
1253 (y + usize::from(mu == 1)) % shape[1],
1254 z,
1255 t,
1256 ]]; let u_mu_shifted = config[[
1259 (x + usize::from(nu == 0)) % shape[0],
1260 (y + usize::from(nu == 1)) % shape[1],
1261 z,
1262 t,
1263 ]]; let u_nu = config[[x, y, z, t]]; let plaquette = u_mu * u_nu_shifted * u_mu_shifted.conj() * u_nu.conj();
1269
1270 Ok(plaquette)
1271 }
1272
1273 fn evaluate_generic_action(&self, config: &Array4<Complex64>) -> Result<f64> {
1275 let lattice_spacing = self.lattice_params.spacing;
1276
1277 let action = config
1279 .iter()
1280 .map(scirs2_core::Complex::norm_sqr)
1281 .sum::<f64>()
1282 * lattice_spacing.powi(4);
1283
1284 Ok(action)
1285 }
1286}
1287
1288impl Default for QFTStats {
1289 fn default() -> Self {
1290 Self {
1291 simulation_time: 0.0,
1292 field_evaluations: 0,
1293 pi_samples: 0,
1294 correlation_calculations: 0,
1295 rg_steps: 0,
1296 avg_plaquette: None,
1297 topological_charge: None,
1298 }
1299 }
1300}
1301
1302#[cfg(test)]
1303mod tests {
1304 use super::*;
1305
1306 #[test]
1307 fn test_qft_simulator_creation() {
1308 let config = QFTConfig::default();
1309 let simulator = QuantumFieldTheorySimulator::new(config);
1310 assert!(simulator.is_ok());
1311 }
1312
1313 #[test]
1314 fn test_scalar_phi4_configuration() {
1315 let mut config = QFTConfig::default();
1316 config.field_theory = FieldTheoryType::ScalarPhi4;
1317 config.lattice_size = vec![8, 8, 8, 16];
1318
1319 let simulator = QuantumFieldTheorySimulator::new(config);
1320 assert!(simulator.is_ok());
1321
1322 let sim = simulator.expect("ScalarPhi4 simulator should be created successfully");
1323 assert!(sim.field_configs.contains_key("phi"));
1324 }
1325
1326 #[test]
1327 fn test_qed_configuration() {
1328 let mut config = QFTConfig::default();
1329 config.field_theory = FieldTheoryType::QED;
1330 config.spacetime_dimensions = 4;
1331
1332 let simulator = QuantumFieldTheorySimulator::new(config);
1333 assert!(simulator.is_ok());
1334
1335 let sim = simulator.expect("QED simulator should be created successfully");
1336 assert!(sim.field_configs.contains_key("psi"));
1337 assert!(sim.field_configs.contains_key("A_0"));
1338 assert!(sim.field_configs.contains_key("A_1"));
1339 assert!(sim.field_configs.contains_key("A_2"));
1340 assert!(sim.field_configs.contains_key("A_3"));
1341 }
1342
1343 #[test]
1344 fn test_path_integral_initialization() {
1345 let config = QFTConfig::default();
1346 let mut simulator = QuantumFieldTheorySimulator::new(config)
1347 .expect("QFT simulator should be created successfully");
1348
1349 let pi_config = PathIntegralConfig {
1350 time_slices: 32,
1351 time_step: 0.1,
1352 action_type: ActionType::Euclidean,
1353 mc_algorithm: MonteCarloAlgorithm::Metropolis,
1354 importance_sampling: true,
1355 target_acceptance_rate: 0.5,
1356 };
1357
1358 let result = simulator.initialize_path_integral(pi_config);
1359 assert!(result.is_ok());
1360 assert!(simulator.path_integral.is_some());
1361 }
1362
1363 #[test]
1364 fn test_gauge_field_setup_u1() {
1365 let config = QFTConfig::default();
1366 let mut simulator = QuantumFieldTheorySimulator::new(config)
1367 .expect("QFT simulator should be created successfully");
1368
1369 let gauge_config = GaugeFieldConfig {
1370 gauge_group: GaugeGroup::U1,
1371 num_colors: 1,
1372 gauge_coupling: 0.1,
1373 gauge_fixing: GaugeFixing::Landau,
1374 wilson_loops: Vec::new(),
1375 };
1376
1377 let result = simulator.setup_gauge_fields(gauge_config);
1378 assert!(result.is_ok());
1379 assert!(simulator.gauge_configs.is_some());
1380 }
1381
1382 #[test]
1383 fn test_gauge_field_setup_su3() {
1384 let config = QFTConfig::default();
1385 let mut simulator = QuantumFieldTheorySimulator::new(config)
1386 .expect("QFT simulator should be created successfully");
1387
1388 let gauge_config = GaugeFieldConfig {
1389 gauge_group: GaugeGroup::SU(3),
1390 num_colors: 3,
1391 gauge_coupling: 0.2,
1392 gauge_fixing: GaugeFixing::Coulomb,
1393 wilson_loops: Vec::new(),
1394 };
1395
1396 let result = simulator.setup_gauge_fields(gauge_config);
1397 assert!(result.is_ok());
1398 assert!(simulator.gauge_configs.is_some());
1399
1400 assert!(simulator.field_configs.contains_key("U_0_00"));
1402 assert!(simulator.field_configs.contains_key("U_0_11"));
1403 assert!(simulator.field_configs.contains_key("U_0_22"));
1404 }
1405
1406 #[test]
1407 fn test_wilson_loop_generation() {
1408 let config = QFTConfig::default();
1409 let simulator = QuantumFieldTheorySimulator::new(config)
1410 .expect("QFT simulator should be created successfully");
1411
1412 let path = simulator
1413 .generate_wilson_loop_path(2, 3)
1414 .expect("Wilson loop path generation should succeed");
1415 assert_eq!(path.len(), 10); assert_eq!(path[0], path[path.len() - 1]);
1419 }
1420
1421 #[test]
1422 fn test_action_evaluation_phi4() {
1423 let config = QFTConfig::default();
1424 let _simulator = QuantumFieldTheorySimulator::new(config)
1425 .expect("QFT simulator should be created successfully");
1426
1427 let lattice_params = LatticeParameters {
1428 spacing: 1.0,
1429 bare_mass: 1.0,
1430 hopping_parameter: 0.125,
1431 plaquette_size: 1,
1432 };
1433
1434 let mut couplings = HashMap::new();
1435 couplings.insert("lambda".to_string(), 0.1);
1436
1437 let evaluator = ActionEvaluator {
1438 theory_type: FieldTheoryType::ScalarPhi4,
1439 couplings,
1440 lattice_params,
1441 };
1442
1443 let field_config = Array4::zeros((4, 4, 4, 4));
1444 let action = evaluator.evaluate_action(&field_config);
1445 assert!(action.is_ok());
1446 assert_eq!(
1447 action.expect("Action evaluation should succeed for zero field"),
1448 0.0
1449 ); }
1451
1452 #[test]
1453 fn test_beta_function_phi4() {
1454 let config = QFTConfig::default();
1455 let simulator = QuantumFieldTheorySimulator::new(config)
1456 .expect("QFT simulator should be created successfully");
1457
1458 let mut couplings = HashMap::new();
1459 couplings.insert("lambda".to_string(), 0.1);
1460
1461 let beta_lambda = simulator.calculate_beta_function("lambda", 1.0, &couplings);
1462 assert!(beta_lambda.is_ok());
1463
1464 let beta_val = beta_lambda.expect("Beta function calculation should succeed");
1465 assert!(beta_val > 0.0); }
1467
1468 #[test]
1469 fn test_beta_function_qed() {
1470 let mut config = QFTConfig::default();
1471 config.field_theory = FieldTheoryType::QED;
1472 let simulator = QuantumFieldTheorySimulator::new(config)
1473 .expect("QED simulator should be created successfully");
1474
1475 let mut couplings = HashMap::new();
1476 couplings.insert("e".to_string(), 0.3);
1477
1478 let beta_e = simulator.calculate_beta_function("e", 1.0, &couplings);
1479 assert!(beta_e.is_ok());
1480
1481 let beta_val = beta_e.expect("QED beta function calculation should succeed");
1482 assert!(beta_val > 0.0); }
1484
1485 #[test]
1486 fn test_beta_function_yang_mills() {
1487 let mut config = QFTConfig::default();
1488 config.field_theory = FieldTheoryType::YangMills;
1489 let simulator = QuantumFieldTheorySimulator::new(config)
1490 .expect("Yang-Mills simulator should be created successfully");
1491
1492 let mut couplings = HashMap::new();
1493 couplings.insert("g".to_string(), 0.5);
1494
1495 let beta_g = simulator.calculate_beta_function("g", 1.0, &couplings);
1496 assert!(beta_g.is_ok());
1497
1498 let beta_val = beta_g.expect("Yang-Mills beta function calculation should succeed");
1499 assert!(beta_val < 0.0); }
1501
1502 #[test]
1503 fn test_rg_flow_analysis() {
1504 let config = QFTConfig::default();
1505 let mut simulator = QuantumFieldTheorySimulator::new(config)
1506 .expect("QFT simulator should be created successfully");
1507
1508 let energy_scales = [0.1, 1.0, 10.0, 100.0];
1509 let rg_flow = simulator.analyze_rg_flow(&energy_scales);
1510 assert!(rg_flow.is_ok());
1511
1512 let flow = rg_flow.expect("RG flow analysis should succeed");
1513 assert!(flow.beta_functions.contains_key("lambda"));
1514 assert!(!flow.fixed_points.is_empty());
1515 assert!(flow
1516 .fixed_points
1517 .iter()
1518 .any(|fp| fp.fp_type == FixedPointType::Gaussian));
1519 }
1520
1521 #[test]
1522 fn test_scattering_cross_section_phi4() {
1523 let config = QFTConfig::default();
1524 let mut simulator = QuantumFieldTheorySimulator::new(config)
1525 .expect("QFT simulator should be created successfully");
1526
1527 let process = ScatteringProcess {
1528 initial_state: vec![
1529 ParticleState {
1530 particle_type: "phi".to_string(),
1531 momentum: [1.0, 0.0, 0.0, 0.0],
1532 spin_state: vec![Complex64::new(1.0, 0.0)],
1533 quantum_numbers: HashMap::new(),
1534 },
1535 ParticleState {
1536 particle_type: "phi".to_string(),
1537 momentum: [-1.0, 0.0, 0.0, 0.0],
1538 spin_state: vec![Complex64::new(1.0, 0.0)],
1539 quantum_numbers: HashMap::new(),
1540 },
1541 ],
1542 final_state: vec![
1543 ParticleState {
1544 particle_type: "phi".to_string(),
1545 momentum: [0.0, 1.0, 0.0, 0.0],
1546 spin_state: vec![Complex64::new(1.0, 0.0)],
1547 quantum_numbers: HashMap::new(),
1548 },
1549 ParticleState {
1550 particle_type: "phi".to_string(),
1551 momentum: [0.0, -1.0, 0.0, 0.0],
1552 spin_state: vec![Complex64::new(1.0, 0.0)],
1553 quantum_numbers: HashMap::new(),
1554 },
1555 ],
1556 cms_energy: 2.0,
1557 scattering_angle: PI / 2.0,
1558 cross_section: None,
1559 s_matrix_element: None,
1560 };
1561
1562 let cross_section = simulator.calculate_scattering_cross_section(&process);
1563 assert!(cross_section.is_ok());
1564
1565 let sigma = cross_section.expect("Cross section calculation should succeed");
1566 assert!(sigma > 0.0);
1567 assert!(sigma.is_finite());
1568 }
1569
1570 #[test]
1571 fn test_field_operator_creation() {
1572 let field_op = FieldOperator {
1573 field_type: FieldOperatorType::Scalar,
1574 position: vec![0.0, 0.0, 0.0, 0.0],
1575 momentum: None,
1576 component: 0,
1577 time_ordering: TimeOrdering::TimeOrdered,
1578 normal_ordering: true,
1579 };
1580
1581 assert_eq!(field_op.field_type, FieldOperatorType::Scalar);
1582 assert_eq!(field_op.position.len(), 4);
1583 assert!(field_op.normal_ordering);
1584 }
1585
1586 #[test]
1587 #[ignore]
1588 fn test_path_integral_monte_carlo_short() {
1589 let config = QFTConfig::default();
1590 let mut simulator = QuantumFieldTheorySimulator::new(config)
1591 .expect("QFT simulator should be created successfully");
1592
1593 let pi_config = PathIntegralConfig {
1594 time_slices: 8,
1595 time_step: 0.1,
1596 action_type: ActionType::Euclidean,
1597 mc_algorithm: MonteCarloAlgorithm::Metropolis,
1598 importance_sampling: true,
1599 target_acceptance_rate: 0.5,
1600 };
1601
1602 simulator
1603 .initialize_path_integral(pi_config)
1604 .expect("Path integral initialization should succeed");
1605
1606 let result = simulator.run_path_integral_mc(100);
1608 assert!(result.is_ok());
1609
1610 let action_history = result.expect("Path integral MC should complete successfully");
1611 assert_eq!(action_history.len(), 100);
1612 assert!(action_history.iter().all(|&a| a.is_finite()));
1613 }
1614
1615 #[test]
1616 #[ignore]
1617 fn test_correlation_function_calculation() {
1618 let config = QFTConfig::default();
1619 let mut simulator = QuantumFieldTheorySimulator::new(config)
1620 .expect("QFT simulator should be created successfully");
1621
1622 let pi_config = PathIntegralConfig {
1623 time_slices: 8,
1624 time_step: 0.1,
1625 action_type: ActionType::Euclidean,
1626 mc_algorithm: MonteCarloAlgorithm::Metropolis,
1627 importance_sampling: true,
1628 target_acceptance_rate: 0.5,
1629 };
1630
1631 simulator
1632 .initialize_path_integral(pi_config)
1633 .expect("Path integral initialization should succeed");
1634
1635 simulator
1637 .run_path_integral_mc(50)
1638 .expect("Path integral MC should complete successfully");
1639
1640 let operators = vec![
1641 FieldOperator {
1642 field_type: FieldOperatorType::Scalar,
1643 position: vec![0.0, 0.0, 0.0, 0.0],
1644 momentum: None,
1645 component: 0,
1646 time_ordering: TimeOrdering::TimeOrdered,
1647 normal_ordering: true,
1648 },
1649 FieldOperator {
1650 field_type: FieldOperatorType::Scalar,
1651 position: vec![1.0, 0.0, 0.0, 0.0],
1652 momentum: None,
1653 component: 0,
1654 time_ordering: TimeOrdering::TimeOrdered,
1655 normal_ordering: true,
1656 },
1657 ];
1658
1659 let correlation = simulator.calculate_correlation_function(&operators, 4);
1660 assert!(correlation.is_ok());
1661
1662 let corr_fn = correlation.expect("Correlation function calculation should succeed");
1663 assert_eq!(corr_fn.separations.len(), 5); assert_eq!(corr_fn.values.len(), 5);
1665 assert_eq!(corr_fn.errors.len(), 5);
1666 }
1667
1668 #[test]
1669 fn test_export_field_configuration() {
1670 let config = QFTConfig::default();
1671 let simulator = QuantumFieldTheorySimulator::new(config)
1672 .expect("QFT simulator should be created successfully");
1673
1674 let field_config = simulator.export_field_configuration("phi");
1675 assert!(field_config.is_ok());
1676
1677 let config_array = field_config.expect("Field configuration export should succeed");
1678 assert_eq!(config_array.ndim(), 4);
1679
1680 let invalid_field = simulator.export_field_configuration("nonexistent");
1682 assert!(invalid_field.is_err());
1683 }
1684
1685 #[test]
1686 fn test_statistics_tracking() {
1687 let config = QFTConfig::default();
1688 let simulator = QuantumFieldTheorySimulator::new(config)
1689 .expect("QFT simulator should be created successfully");
1690
1691 let stats = simulator.get_statistics();
1692 assert_eq!(stats.field_evaluations, 0);
1693 assert_eq!(stats.pi_samples, 0);
1694 assert_eq!(stats.correlation_calculations, 0);
1695 assert_eq!(stats.rg_steps, 0);
1696 }
1697}