use scirs2_fft::{fht, fht_sample_points, fhtoffset, ifht};
#[allow(dead_code)]
fn bessel_j0(x: f64) -> f64 {
if x.abs() < 1e-6 {
1.0
} else {
(x.sin() / x) * (1.0 - x * x / 6.0 + x.powi(4) / 120.0)
}
}
#[allow(dead_code)]
fn main() {
println!("Fast Hankel Transform Example");
println!("============================");
println!();
example_basic_fht();
example_different_orders();
example_biased_transform();
example_optimal_offset();
}
#[allow(dead_code)]
fn example_basic_fht() {
println!("Example 1: Basic FHT with order 0");
println!("---------------------------------");
let n = 128;
let dln = 0.05;
let mu = 0.0;
let r = fht_sample_points(n, dln, 0.0);
let sigma = 1.0;
let f: Vec<f64> = r
.iter()
.map(|&ri| (-ri * ri / (2.0 * sigma * sigma)).exp())
.collect();
let f_transform = fht(&f, dln, mu, None, None).expect("Operation failed");
println!("Input: Gaussian with σ = {sigma}");
println!("Transform: Should be Gaussian with σ' ≈ {}", 1.0 / sigma);
let max_idx = f_transform
.iter()
.position(|&x| x == f_transform.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)))
.expect("Operation failed");
println!("Peak at index: {max_idx}");
let f_recovered = ifht(&f_transform, dln, mu, None, None).expect("Operation failed");
let error: f64 = f
.iter()
.zip(f_recovered.iter())
.map(|(&a, &b)| (a - b).abs())
.sum::<f64>()
/ n as f64;
println!("Average recovery error: {error:.2e}");
println!();
}
#[allow(dead_code)]
fn example_different_orders() {
println!("Example 2: FHT with different orders");
println!("-----------------------------------");
let n = 64;
let dln = 0.1;
let orders = vec![0.0, 0.5, 1.0, 2.0];
for mu in orders {
println!("Testing order μ = {mu}");
let r = fht_sample_points(n, dln, 0.0);
let f: Vec<f64> = r.iter().map(|&ri| (-ri).exp()).collect();
let f_transform = fht(&f, dln, mu, None, None).expect("Operation failed");
let has_nan = f_transform.iter().any(|x| x.is_nan());
println!(" Transform successful: {}", !has_nan);
let norm: f64 = f_transform.iter().map(|x| x * x).sum::<f64>().sqrt();
println!(" Transform norm: {norm:.3e}");
}
println!();
}
#[allow(dead_code)]
fn example_biased_transform() {
println!("Example 3: Biased transform for power laws");
println!("-----------------------------------------");
let n = 128;
let dln = 0.05;
let mu = 0.0;
let alpha = 1.5;
let r = fht_sample_points(n, dln, 0.0);
let f: Vec<f64> = r.iter().map(|&ri| ri.powf(-alpha)).collect();
let f_unbiased = fht(&f, dln, mu, None, None).expect("Operation failed");
let f_biased = fht(&f, dln, mu, None, Some(alpha)).expect("Operation failed");
let norm_unbiased: f64 = f_unbiased.iter().map(|x| x * x).sum::<f64>().sqrt();
let norm_biased: f64 = f_biased.iter().map(|x| x * x).sum::<f64>().sqrt();
println!("Power law: r^(-{alpha})");
println!("Unbiased transform norm: {norm_unbiased:.3e}");
println!("Biased transform norm: {norm_biased:.3e}");
println!(
"Ratio (biased/unbiased): {:.3}",
norm_biased / norm_unbiased
);
println!();
}
#[allow(dead_code)]
fn example_optimal_offset() {
println!("Example 4: Optimal offset calculation");
println!("------------------------------------");
let dln = 0.1;
let mu = 0.5;
let bias_values = vec![0.0, 0.5, 1.0, 2.0];
for bias in bias_values {
let offset = fhtoffset(dln, mu, None, Some(bias)).expect("Operation failed");
println!("Bias = {bias}, Optimal offset = {offset}");
}
println!();
let n = 64;
let offsets = vec![0.0, 0.1, 0.2, 0.5];
let r = fht_sample_points(n, dln, 0.0);
let f: Vec<f64> = r.iter().map(|&ri| (-ri * ri).exp()).collect();
println!("Effect of offset on transform:");
for offset in offsets {
let f_transform = fht(&f, dln, mu, Some(offset), None).expect("Operation failed");
let norm: f64 = f_transform.iter().map(|x| x * x).sum::<f64>().sqrt();
println!(" Offset = {offset}, Transform norm = {norm:.3e}");
}
println!();
}
#[allow(dead_code)]
fn example_radial_transform() {
println!("Example 5: Radial function transform");
println!("-----------------------------------");
let n = 128;
let dln = 0.05;
let mu = 0.0;
let r = fht_sample_points(n, dln, -2.0); let f: Vec<f64> = r
.iter()
.map(|&ri| {
let x = ri * ri;
(1.0 - x) * (-x / 2.0).exp()
})
.collect();
let f_transform = fht(&f, dln, mu, None, None).expect("Operation failed");
println!("Mexican hat wavelet in real space");
println!("Hankel transform gives radial frequency profile");
let k = fht_sample_points(n, dln, -2.0);
let max_idx = f_transform
.iter()
.enumerate()
.max_by(|(_, a), (_, b)| a.partial_cmp(b).expect("Operation failed"))
.map(|(idx, _)| idx)
.expect("Operation failed");
println!("Peak frequency at k ≈ {:.3}", k[max_idx]);
println!();
}