use crate::PhysicsError;
pub fn gell_mann_matrices() -> [[f64; 9]; 8] {
let lambda1 = [0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let lambda2 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let lambda3 = [1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0];
let lambda4 = [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0];
let lambda5 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let lambda6 = [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0];
let lambda7 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let inv_sqrt3 = 1.0 / 3.0_f64.sqrt();
let lambda8 = [
inv_sqrt3,
0.0,
0.0,
0.0,
inv_sqrt3,
0.0,
0.0,
0.0,
-2.0 * inv_sqrt3,
];
[
lambda1, lambda2, lambda3, lambda4, lambda5, lambda6, lambda7, lambda8,
]
}
pub fn structure_constant(a: usize, b: usize, c: usize) -> f64 {
let half = 0.5;
let sqrt3_half = 3.0_f64.sqrt() * 0.5;
let mut indices = [a, b, c];
let mut sign = 1.0;
for i in 0..2 {
for j in 0..2 - i {
if indices[j] > indices[j + 1] {
indices.swap(j, j + 1);
sign *= -1.0;
}
}
}
let [i, j, k] = indices;
let value = match (i, j, k) {
(1, 2, 3) => 1.0,
(1, 4, 7) => half,
(1, 5, 6) => -half, (2, 4, 6) => half,
(2, 5, 7) => half,
(3, 4, 5) => half,
(3, 6, 7) => -half, (4, 5, 8) => sqrt3_half,
(6, 7, 8) => sqrt3_half,
_ => 0.0,
};
sign * value
}
pub fn all_structure_constants() -> Vec<(usize, usize, usize, f64)> {
let half = 0.5;
let sqrt3_half = 3.0_f64.sqrt() * 0.5;
vec![
(1, 2, 3, 1.0),
(1, 4, 7, half),
(1, 6, 5, half), (2, 4, 6, half),
(2, 5, 7, half),
(3, 4, 5, half),
(3, 7, 6, half), (4, 5, 8, sqrt3_half),
(6, 7, 8, sqrt3_half),
]
}
pub fn covariant_derivative_kernel(
psi: &[f64], psi_gradient: &[f64], gluon_field: &[f64], coupling: f64,
) -> Result<Vec<f64>, PhysicsError> {
if psi.len() != 6 {
return Err(PhysicsError::DimensionMismatch(format!(
"Psi must have 6 components (3 complex), got {}",
psi.len()
)));
}
if psi_gradient.len() != 24 {
return Err(PhysicsError::DimensionMismatch(format!(
"Psi gradient must have 24 components, got {}",
psi_gradient.len()
)));
}
if gluon_field.len() != 32 {
return Err(PhysicsError::DimensionMismatch(format!(
"Gluon field must have 32 components, got {}",
gluon_field.len()
)));
}
let matrices = gell_mann_matrices();
let mut result = vec![0.0; 24];
for mu in 0..4 {
for c in 0..6 {
result[mu * 6 + c] = psi_gradient[mu * 6 + c];
}
for a in 0..8 {
let a_mu_a = gluon_field[mu * 8 + a];
let lambda = &matrices[a];
for i in 0..3 {
for j in 0..3 {
let m_ij = lambda[i * 3 + j] * 0.5; if m_ij != 0.0 {
let psi_re = psi[j * 2];
let psi_im = psi[j * 2 + 1];
let factor = coupling * a_mu_a * m_ij;
result[mu * 6 + i * 2] -= factor * psi_im;
result[mu * 6 + i * 2 + 1] += factor * psi_re;
}
}
}
}
}
if result.iter().any(|v| !v.is_finite()) {
return Err(PhysicsError::NumericalInstability(
"Non-finite result in covariant derivative".into(),
));
}
Ok(result)
}
pub fn wilson_loop_kernel(
gluon_values: &[f64],
path_lengths: &[f64],
coupling: f64,
) -> Result<f64, PhysicsError> {
let num_segments = path_lengths.len();
if gluon_values.len() != num_segments * 8 {
return Err(PhysicsError::DimensionMismatch(format!(
"Expected {} gluon values for {} segments, got {}",
num_segments * 8,
num_segments,
gluon_values.len()
)));
}
if num_segments == 0 {
return Ok(3.0); }
let mut phase_sum = 0.0;
for i in 0..num_segments {
let dl = path_lengths[i];
let mut a_squared = 0.0;
for a in 0..8 {
let a_a = gluon_values[i * 8 + a];
a_squared += a_a * a_a;
}
phase_sum += a_squared * dl * dl;
}
let w = 3.0 * (-0.5 * coupling * coupling * phase_sum).exp();
if !w.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Non-finite Wilson loop result".into(),
));
}
Ok(w)
}
pub fn confinement_potential_kernel(
distance: f64,
string_tension: f64,
coulomb_term: Option<f64>,
) -> Result<f64, PhysicsError> {
if distance <= 0.0 {
return Err(PhysicsError::PhysicalInvariantBroken(
"Distance must be positive".into(),
));
}
if !distance.is_finite() || !string_tension.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Non-finite input to confinement potential".into(),
));
}
let mut v = string_tension * distance;
if let Some(alpha) = coulomb_term {
if !alpha.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Non-finite Coulomb coefficient".into(),
));
}
v -= alpha / distance;
}
Ok(v)
}
pub fn running_coupling_kernel(
q_squared: f64,
lambda_qcd: f64,
n_flavors: u32,
) -> Result<f64, PhysicsError> {
if q_squared <= 0.0 {
return Err(PhysicsError::PhysicalInvariantBroken(
"Q² must be positive".into(),
));
}
if lambda_qcd <= 0.0 {
return Err(PhysicsError::PhysicalInvariantBroken(
"Lambda_QCD must be positive".into(),
));
}
let lambda_squared = lambda_qcd * lambda_qcd;
if q_squared <= lambda_squared {
return Err(PhysicsError::PhysicalInvariantBroken(
"Q² must be greater than Λ_QCD² for perturbative regime".into(),
));
}
let b0 = 11.0 - (2.0 * n_flavors as f64) / 3.0;
if b0 <= 0.0 {
return Err(PhysicsError::PhysicalInvariantBroken(format!(
"Too many flavors ({}): b0 = {} <= 0",
n_flavors, b0
)));
}
let log_ratio = (q_squared / lambda_squared).ln();
let alpha_s = 4.0 * std::f64::consts::PI / (b0 * log_ratio);
if !alpha_s.is_finite() || alpha_s <= 0.0 {
return Err(PhysicsError::NumericalInstability(format!(
"Invalid running coupling: α_s = {}",
alpha_s
)));
}
Ok(alpha_s)
}