use mdarray::{DTensor, DynRank, Shape, Tensor, expr};
use num_complex::{Complex, ComplexFloat};
use sparse_ir::{
Bosonic, DiscreteLehmannRepresentation, Fermionic, FiniteTempBasis, LogisticKernel,
MatsubaraSampling, RegularizedBoseKernel, TauSampling,
basis_trait::Basis,
gemm::matmul_par,
kernel::{CentrosymmKernel, KernelProperties},
sampling::movedim,
sve::{SVEResult, TworkType, compute_sve},
traits::StatisticsType,
};
use std::ops::Sub;
fn max_relative_error<T>(a: &Tensor<T, DynRank>, b: &Tensor<T, DynRank>) -> f64
where
T: ComplexFloat<Real = f64> + Sub<Output = T>,
{
let max_diff = expr::fold(expr::zip(a.expr(), b.expr()), 0.0_f64, |acc, (x, y)| {
acc.max((*x - *y).abs())
});
let max_ref = expr::fold(a.expr(), 0.0_f64, |acc, x| acc.max(x.abs()));
if max_ref < 1e-15 {
max_diff
} else {
max_diff / max_ref
}
}
fn max_relative_error_real(a: &Tensor<f64, DynRank>, b: &Tensor<f64, DynRank>) -> f64 {
max_relative_error(a, b)
}
fn max_relative_error_complex(
a: &Tensor<Complex<f64>, DynRank>,
b: &Tensor<Complex<f64>, DynRank>,
) -> f64 {
max_relative_error(a, b)
}
fn get_dims(target_dim_size: usize, extra_dims: &[usize], target_dim: usize) -> Vec<usize> {
let ndim = 1 + extra_dims.len();
let mut dims = vec![0; ndim];
dims[target_dim] = target_dim_size;
let mut pos = 0;
for i in 0..ndim {
if i == target_dim {
continue;
}
dims[i] = extra_dims[pos];
pos += 1;
}
dims
}
fn contract_along_dim<T>(
matrix: &DTensor<T, 2>,
coeffs: &Tensor<T, DynRank>,
target_dim: usize,
) -> Tensor<T, DynRank>
where
T: num_complex::ComplexFloat + faer_traits::ComplexField + num_traits::One + Copy + 'static,
{
let (n_points, n_poles) = *matrix.shape();
let rank = coeffs.rank();
assert!(
target_dim < rank,
"target_dim {} must be < rank {}",
target_dim,
rank
);
assert_eq!(
coeffs.shape().dim(target_dim),
n_poles,
"coeffs.shape().dim({}) = {} must equal n_poles = {}",
target_dim,
coeffs.shape().dim(target_dim),
n_poles
);
let coeffs_dim0 = movedim(coeffs, target_dim, 0);
let extra_size = coeffs_dim0.len() / n_poles;
let coeffs_2d_dyn = coeffs_dim0.reshape(&[n_poles, extra_size][..]).to_tensor();
let coeffs_2d = DTensor::<T, 2>::from_fn([n_poles, extra_size], |idx| {
coeffs_2d_dyn[&[idx[0], idx[1]][..]]
});
let result_2d = matmul_par(matrix, &coeffs_2d, None);
let mut result_shape = vec![n_points];
coeffs_dim0.shape().with_dims(|dims| {
for i in 1..dims.len() {
result_shape.push(dims[i]);
}
});
let result_dim0 = result_2d.into_dyn().reshape(&result_shape[..]).to_tensor();
movedim(&result_dim0, 0, target_dim)
}
fn random_pole_coeff(seed: u64, idx: &[usize], pole: f64) -> f64 {
let mut index = 0u64;
for &dim_val in idx.iter() {
index = index.wrapping_mul(1000).wrapping_add(dim_val as u64);
}
let mut x = seed.wrapping_add(index);
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
let random_val = (x as f64) / (u64::MAX as f64);
(2.0 * random_val - 1.0) * pole.abs().sqrt()
}
fn create_random_dlr_coeffs(
n_poles: usize,
extra_dims: &[usize],
seed: u64,
poles: &[f64],
target_dim: usize,
) -> Tensor<f64, DynRank> {
let dims = get_dims(n_poles, extra_dims, target_dim);
let ndim = dims.len();
assert!(ndim >= 1, "dims must have at least one dimension");
assert!(target_dim < ndim, "invalid target_dim");
let total_size: usize = dims.iter().product();
let n_rest = total_size / n_poles;
let mut coeffs_2d = DTensor::<f64, 2>::from_elem([n_poles, n_rest], 0.0);
for i in 0..n_poles {
let pole = poles[i];
for j in 0..n_rest {
let idx_2d = [i, j];
coeffs_2d[[i, j]] = random_pole_coeff(seed, &idx_2d, pole);
}
}
let mut shape_dim0 = Vec::with_capacity(ndim);
shape_dim0.push(n_poles);
for (k, &d) in dims.iter().enumerate() {
if k == target_dim {
continue;
}
shape_dim0.push(d);
}
let coeffs_dim0 = coeffs_2d.into_dyn().reshape(&shape_dim0[..]).to_tensor();
movedim(&coeffs_dim0, 0, target_dim)
}
fn run_integration_example_single<K, S>(
beta: f64,
omega_max: f64,
epsilon: f64,
tol: f64,
extra_dims: &[usize],
target_dim: usize,
positive_only: bool,
kernel: &K,
sve: &SVEResult,
) where
K: CentrosymmKernel + KernelProperties + Clone + 'static,
S: StatisticsType + 'static,
{
let ndim = 1 + extra_dims.len();
let stat_name = if S::STATISTICS == sparse_ir::traits::Statistics::Fermionic {
"Fermionic"
} else {
"Bosonic"
};
println!("========================================");
println!(
"Integration Example ({}D, target_dim={}, {}, positive_only={})",
ndim, target_dim, stat_name, positive_only
);
println!("========================================");
println!("Parameters:");
println!(" beta = {}", beta);
println!(" omega_max = {}", omega_max);
println!(" epsilon = {}", epsilon);
println!(" tolerance = {}", tol);
println!(" extra_dims = {:?}", extra_dims);
println!(" target_dim = {}", target_dim);
println!(" statistics = {}", stat_name);
println!(" positive_only = {}", positive_only);
println!();
println!("Step 1: Creating kernel and IR basis...");
let basis = FiniteTempBasis::<_, S>::from_sve_result(
kernel.clone(),
beta,
sve.clone(),
Some(epsilon),
None,
);
let basis_size = basis.size();
println!(" Basis size: {}", basis_size);
println!();
println!("Step 2: Creating sampling objects...");
let tau_points = basis.default_tau_sampling_points();
let n_tau = tau_points.len();
println!(" Number of tau points: {}", n_tau);
let tau_sampling = TauSampling::<S>::with_sampling_points(&basis, tau_points.clone());
let matsubara_points = basis.default_matsubara_sampling_points(positive_only);
let n_matsubara = matsubara_points.len();
println!(" Number of Matsubara points: {}", n_matsubara);
let matsubara_sampling =
MatsubaraSampling::<S>::with_sampling_points(&basis, matsubara_points.clone());
println!();
println!("Step 3: Creating DLR representation...");
let dlr = DiscreteLehmannRepresentation::<S>::new(&basis);
let n_poles = dlr.poles.len();
println!(" Number of DLR poles: {}", n_poles);
println!();
println!("Step 4: Generating random DLR coefficients...");
let seed = 982743u64;
let dlr_coeffs = create_random_dlr_coeffs(n_poles, extra_dims, seed, &dlr.poles, target_dim);
println!(
" Generated DLR coefficients with shape: {:?}",
dlr_coeffs.shape().dims()
);
println!();
println!("Step 5: Converting DLR coefficients to IR...");
let ir_coeffs = dlr.to_ir_nd(None, &dlr_coeffs, target_dim);
println!(" IR coefficients shape: {:?}", ir_coeffs.shape().dims());
println!();
println!("Step 6: Evaluating on tau grid...");
let g_tau_ir = tau_sampling.evaluate_nd(None, &ir_coeffs, target_dim);
println!(" g_tau_ir shape: {:?}", g_tau_ir.shape().dims());
let dlr_u_tau = <DiscreteLehmannRepresentation<S> as Basis<S>>::evaluate_tau(&dlr, &tau_points);
let g_tau_dlr = contract_along_dim(&dlr_u_tau, &dlr_coeffs, target_dim);
let tau_error = max_relative_error_real(&g_tau_ir, &g_tau_dlr);
println!(" Max relative error (IR vs DLR on tau): {:.2e}", tau_error);
if tau_error > tol {
println!(" WARNING: Error exceeds tolerance!");
}
println!();
println!("Step 7: Evaluating on Matsubara grid...");
let g_iw_ir = matsubara_sampling.evaluate_nd(None, &ir_coeffs, target_dim);
println!(" g_iw_ir shape: {:?}", g_iw_ir.shape().dims());
let dlr_uhat_matsu =
<DiscreteLehmannRepresentation<S> as Basis<S>>::evaluate_matsubara(&dlr, &matsubara_points);
let dlr_coeffs_complex: Tensor<Complex<f64>, DynRank> =
expr::FromExpression::from_expr(expr::map(dlr_coeffs.expr(), |x| Complex::new(*x, 0.0)));
let g_iw_dlr = contract_along_dim(&dlr_uhat_matsu, &dlr_coeffs_complex, target_dim);
let matsubara_error = max_relative_error_complex(&g_iw_ir, &g_iw_dlr);
println!(
" Max relative error (IR vs DLR on Matsubara): {:.2e}",
matsubara_error
);
if matsubara_error > tol {
println!(" WARNING: Error exceeds tolerance!");
}
println!();
println!("Step 8: Round-trip test (tau → IR → Matsubara)...");
let ir_coeffs_recovered = tau_sampling.fit_nd(None, &g_tau_ir, target_dim);
println!(
" Recovered IR coefficients shape: {:?}",
ir_coeffs_recovered.shape().dims()
);
let ir_recovery_error = max_relative_error_real(&ir_coeffs, &ir_coeffs_recovered);
println!(
" Max relative error (IR recovery): {:.2e}",
ir_recovery_error
);
if ir_recovery_error > tol {
println!(" WARNING: Error exceeds tolerance!");
}
let ir_coeffs_recovered_complex: Tensor<Complex<f64>, DynRank> =
expr::FromExpression::from_expr(expr::map(ir_coeffs_recovered.expr(), |x| {
Complex::new(*x, 0.0)
}));
let g_iw_ir_reconst =
matsubara_sampling.evaluate_nd(None, &ir_coeffs_recovered_complex, target_dim);
let roundtrip_error = max_relative_error_complex(&g_iw_ir, &g_iw_ir_reconst);
println!(
" Max relative error (Matsubara round-trip): {:.2e}",
roundtrip_error
);
if roundtrip_error > tol {
println!(" WARNING: Error exceeds tolerance!");
}
println!();
println!("Step 9: Round-trip test (DLR → IR → DLR)...");
let dlr_coeffs_recovered = dlr.from_ir_nd(None, &ir_coeffs, target_dim);
let dlr_recovery_error = max_relative_error_real(&dlr_coeffs, &dlr_coeffs_recovered);
println!(
" Max relative error (DLR recovery): {:.2e}",
dlr_recovery_error
);
if dlr_recovery_error > tol {
println!(" WARNING: Error exceeds tolerance!");
}
println!();
println!("========================================");
println!(
"Summary ({}D, target_dim={}, {}, positive_only={}):",
ndim, target_dim, stat_name, positive_only
);
println!(" Tau evaluation error (IR vs DLR): {:.2e}", tau_error);
println!(
" Matsubara evaluation error (IR vs DLR): {:.2e}",
matsubara_error
);
println!(" IR recovery error (tau fit): {:.2e}", ir_recovery_error);
println!(" Matsubara round-trip error: {:.2e}", roundtrip_error);
println!(" DLR recovery error: {:.2e}", dlr_recovery_error);
println!("========================================");
}
fn run_integration_example(beta: f64, omega_max: f64, epsilon: f64, tol: f64) {
let lambda = beta * omega_max;
let kernel = LogisticKernel::new(lambda);
println!();
println!(
"Testing with beta = {}, omega_max = {}, epsilon = {}",
beta, omega_max, epsilon
);
println!("Computing SVE for all tests");
let sve = compute_sve(kernel.clone(), epsilon, None, None, TworkType::Auto);
println!("SVE computed");
println!();
run_integration_example_for_stat::<LogisticKernel, Fermionic>(
beta, omega_max, epsilon, tol, &kernel, &sve,
);
run_integration_example_for_stat::<LogisticKernel, Bosonic>(
beta, omega_max, epsilon, tol, &kernel, &sve,
);
}
fn run_integration_example_regularized_bose(beta: f64, omega_max: f64, epsilon: f64, tol: f64) {
let _lambda_physical = beta * omega_max;
let lambda = 1e2;
let kernel = RegularizedBoseKernel::new(lambda);
println!();
println!(
"Testing RegularizedBoseKernel with beta = {}, omega_max = {}, lambda = {}, epsilon = {}",
beta, omega_max, lambda, epsilon
);
println!("Computing SVE for all tests");
let sve = compute_sve(kernel.clone(), epsilon, None, None, TworkType::Auto);
println!("SVE computed");
println!();
run_integration_example_for_stat::<RegularizedBoseKernel, Bosonic>(
beta, omega_max, epsilon, tol, &kernel, &sve,
);
}
fn run_integration_example_for_stat<K, S>(
beta: f64,
omega_max: f64,
epsilon: f64,
tol: f64,
kernel: &K,
sve: &SVEResult,
) where
K: CentrosymmKernel + KernelProperties + Clone + 'static,
S: StatisticsType + 'static,
{
for positive_only in [false, true] {
println!("positive_only = {}", positive_only);
let extra_dims_configs: Vec<Vec<usize>> = vec![vec![], vec![2, 3, 4]];
for extra_dims in extra_dims_configs {
let ndim = 1 + extra_dims.len();
let target_dim_start = 0;
let target_dim_end = if extra_dims.is_empty() { 0 } else { ndim - 1 };
for target_dim in target_dim_start..=target_dim_end {
run_integration_example_single::<K, S>(
beta,
omega_max,
epsilon,
tol,
&extra_dims,
target_dim,
positive_only,
kernel,
sve,
);
println!();
}
}
}
}
fn main() {
let beta = 1e4;
let omega_max = 2.0;
let epsilon = 1e-10;
let tol = 10.0 * epsilon;
run_integration_example(beta, omega_max, epsilon, tol);
run_integration_example_regularized_bose(beta, omega_max, epsilon, tol);
}