use crate::{
BandDrudeWeight, Energy, Length, PhysicsError, QuantumEigenvector, QuantumMetric,
QuantumVelocity,
};
use deep_causality_num::Complex;
pub fn quantum_geometric_tensor_kernel(
eigenvalues: &deep_causality_tensor::CausalTensor<f64>,
eigenvectors: &QuantumEigenvector,
velocity_i: &QuantumVelocity,
velocity_j: &QuantumVelocity,
band_n: usize,
regularization: f64,
) -> Result<Complex<f64>, PhysicsError> {
let ev_data = eigenvectors.inner().as_slice();
let vi_data = velocity_i.inner().as_slice();
let vj_data = velocity_j.inner().as_slice();
let energies = eigenvalues.as_slice();
let shape = eigenvectors.inner().shape();
if shape.len() != 2 {
return Err(PhysicsError::DimensionMismatch(
"Eigenvectors must be Rank 2".into(),
));
}
let basis_size = shape[0];
let num_states = shape[1];
if band_n >= num_states {
return Err(PhysicsError::DimensionMismatch(format!(
"Band index {} out of bounds (max {})",
band_n,
num_states - 1
)));
}
if energies.len() != num_states {
return Err(PhysicsError::DimensionMismatch(
"Eigenvalues length mismatch".into(),
));
}
let inner_prod =
|col_u: usize, col_v_matrix: &[Complex<f64>], col_v_idx: usize| -> Complex<f64> {
let mut sum = Complex::new(0.0, 0.0);
for b in 0..basis_size {
let idx_u = b * num_states + col_u;
let idx_v = b * num_states + col_v_idx;
let u_val = ev_data[idx_u];
let v_val = col_v_matrix[idx_v];
sum += Complex::new(u_val.re, -u_val.im) * v_val;
}
sum
};
let e_n = energies[band_n];
let mut q_sum = Complex::new(0.0, 0.0);
for (m, &e_m) in energies.iter().enumerate() {
if m == band_n {
continue;
}
let diff = e_n - e_m;
let denom = diff * diff + regularization;
let term1 = inner_prod(band_n, vi_data, m);
let term2 = inner_prod(m, vj_data, band_n);
let numerator = term1 * term2;
q_sum += numerator / denom;
}
Ok(q_sum)
}
pub fn quasi_qgt_kernel(
eigenvalues: &deep_causality_tensor::CausalTensor<f64>,
eigenvectors: &QuantumEigenvector,
velocity_i: &QuantumVelocity,
velocity_j: &QuantumVelocity,
band_n: usize,
regularization: f64,
) -> Result<Complex<f64>, PhysicsError> {
quantum_geometric_tensor_kernel(
eigenvalues,
eigenvectors,
velocity_i,
velocity_j,
band_n,
regularization,
)
}
pub fn effective_band_drude_weight_kernel(
energy_n: Energy<f64>,
energy_0: Energy<f64>,
curvature_ii: f64,
quantum_metric: QuantumMetric<f64>,
lattice_const: Length<f64>,
) -> Result<BandDrudeWeight<f64>, PhysicsError> {
if !curvature_ii.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Band curvature is not finite".into(),
));
}
let a = lattice_const.value();
if a <= 0.0 {
return Err(PhysicsError::PhysicalInvariantBroken(format!(
"Lattice constant must be positive, got {}",
a
)));
}
let gap = (energy_n.value() - energy_0.value()).abs();
let geom_term = gap * quantum_metric.value();
let dimensionless_weight = curvature_ii + geom_term;
let scale_factor = a * a;
let physical_weight = dimensionless_weight * scale_factor;
if !physical_weight.is_finite() {
return Err(PhysicsError::NumericalInstability(
"Resulting Drude Weight is not finite".into(),
));
}
BandDrudeWeight::new(physical_weight)
}