use mdarray::{DynRank, Tensor};
use num_complex::Complex;
pub fn movedim<T: Clone>(arr: &Tensor<T, DynRank>, src: usize, dst: usize) -> Tensor<T, DynRank> {
let rank = arr.rank();
assert!(
src < rank && dst < rank,
"src={}, dst={} must be < rank={}",
src,
dst,
rank
);
if src == dst {
return arr.clone();
}
let mut perm: Vec<usize> = (0..rank).collect();
perm.remove(src);
perm.insert(dst, src);
arr.permute(&perm[..]).to_tensor()
}
pub struct SimpleRng {
state: u64,
}
impl SimpleRng {
pub fn new(seed: u64) -> Self {
Self { state: seed }
}
pub fn next_f64(&mut self) -> f64 {
self.state = self.state.wrapping_mul(1664525).wrapping_add(1013904223);
((self.state >> 16) as f64) / ((1u64 << 48) as f64)
}
pub fn next<T: RandomGenerate>(&mut self) -> T {
T::generate(self)
}
}
pub trait RandomGenerate {
fn generate(rng: &mut SimpleRng) -> Self;
}
impl RandomGenerate for f64 {
fn generate(rng: &mut SimpleRng) -> Self {
rng.next_f64()
}
}
impl RandomGenerate for Complex<f64> {
fn generate(rng: &mut SimpleRng) -> Self {
let re = rng.next_f64();
let im = rng.next_f64();
Complex::new(re, im)
}
}
pub trait ErrorNorm {
fn error_norm(self) -> f64;
}
pub trait ConvertFromReal {
fn from_real(value: f64) -> Self;
}
impl ConvertFromReal for f64 {
fn from_real(value: f64) -> Self {
value
}
}
impl ConvertFromReal for Complex<f64> {
fn from_real(value: f64) -> Self {
Complex::new(value, 0.0)
}
}
impl ErrorNorm for f64 {
fn error_norm(self) -> f64 {
self.abs()
}
}
impl ErrorNorm for Complex<f64> {
fn error_norm(self) -> f64 {
self.norm() }
}
pub fn generate_test_data_tau_and_matsubara<T, S, K>(
basis: &crate::FiniteTempBasis<K, S>,
tau_points: &[f64],
matsubara_freqs: &[crate::freq::MatsubaraFreq<S>],
seed: u64,
) -> (Vec<T>, Vec<T>, Vec<Complex<f64>>)
where
T: RandomGenerate + ConvertFromReal + Clone + std::ops::Mul<f64, Output = T>,
S: crate::traits::StatisticsType,
K: crate::kernel::KernelProperties + crate::kernel::CentrosymmKernel + Clone + 'static,
{
use crate::giwn_single_pole;
let mut rng = SimpleRng::new(seed);
let basis_size = basis.size();
let beta = basis.beta();
let wmax = basis.kernel().lambda() / beta;
let omega = wmax * 0.5;
let coeffs: Vec<T> = (0..basis_size)
.map(|l| rng.next::<T>() * basis.s()[l])
.collect();
let gtau_values: Vec<T> = tau_points
.iter()
.map(|&tau| {
let g = crate::gtau_single_pole::<S>(tau, omega, beta);
T::from_real(g)
})
.collect();
let giwn_values: Vec<Complex<f64>> = matsubara_freqs
.iter()
.map(|freq| giwn_single_pole::<S>(freq, omega, beta))
.collect();
(coeffs, gtau_values, giwn_values)
}
pub fn generate_nd_test_data<T, S, K>(
basis: &crate::FiniteTempBasis<K, S>,
tau_points: &[f64],
matsubara_freqs: &[crate::freq::MatsubaraFreq<S>],
seed: u64,
extra_dims: &[usize],
) -> (
Tensor<T, DynRank>,
Tensor<T, DynRank>,
Tensor<num_complex::Complex<f64>, DynRank>,
)
where
T: RandomGenerate
+ ConvertFromReal
+ Clone
+ std::ops::Mul<f64, Output = T>
+ Default
+ From<f64>
+ std::ops::Sub<Output = T>
+ std::ops::Mul<Output = T>,
S: crate::traits::StatisticsType,
K: crate::kernel::KernelProperties + crate::kernel::CentrosymmKernel + Clone + 'static,
{
use crate::{giwn_single_pole, gtau_single_pole};
let mut rng = SimpleRng::new(seed);
let beta = basis.beta();
let wmax = basis.kernel().lambda() / beta;
let basis_size = basis.size();
let total_extra: usize = extra_dims.iter().product();
let total_extra = if total_extra == 0 { 1 } else { total_extra };
let mut coeffs_shape = vec![basis_size];
coeffs_shape.extend_from_slice(extra_dims);
let mut coeffs: Tensor<T, DynRank> = Tensor::zeros(&coeffs_shape[..]);
let mut gtau_shape = vec![tau_points.len()];
gtau_shape.extend_from_slice(extra_dims);
let mut gtau_values: Tensor<T, DynRank> = Tensor::zeros(>au_shape[..]);
let mut giwn_shape = vec![matsubara_freqs.len()];
giwn_shape.extend_from_slice(extra_dims);
let mut giwn_values: Tensor<Complex<f64>, DynRank> = Tensor::zeros(&giwn_shape[..]);
for flat_idx in 0..total_extra {
let mut extra_idx = Vec::new();
let mut remainder = flat_idx;
for &dim_size in extra_dims.iter().rev() {
extra_idx.push(remainder % dim_size);
remainder /= dim_size;
}
extra_idx.reverse();
for l in 0..basis_size {
let random_base: T = rng.next();
let random_centered = random_base * T::from(2.0) - T::from(1.0);
let scaled_coeff = random_centered * basis.s()[l];
let mut full_idx = vec![l];
full_idx.extend_from_slice(&extra_idx);
coeffs[&full_idx[..]] = scaled_coeff;
}
let omega = wmax * (0.3 + rng.next_f64() * 0.4);
for (i, &tau) in tau_points.iter().enumerate() {
let g = gtau_single_pole::<S>(tau, omega, beta);
let mut full_idx = vec![i];
full_idx.extend_from_slice(&extra_idx);
gtau_values[&full_idx[..]] = T::from_real(g);
}
for (i, freq) in matsubara_freqs.iter().enumerate() {
let g = giwn_single_pole::<S>(freq, omega, beta);
let mut full_idx = vec![i];
full_idx.extend_from_slice(&extra_idx);
giwn_values[&full_idx[..]] = g;
}
}
(coeffs, gtau_values, giwn_values)
}