use std::collections::HashSet;
use ndarray::{Array2, ArrayBase, ArrayView1, AsArray, Axis, Ix1, Ix3, ViewRepr, Zip};
use crate::prelude::*;
#[inline]
pub fn gs_mask<'a, T, A, B>(
data: A,
g_coords: B,
s_coords: B,
axis: Option<usize>,
threads: Option<usize>,
) -> Result<Array2<bool>, ImgalError>
where
A: AsArray<'a, T, Ix3>,
B: AsArray<'a, f64, Ix1>,
T: 'a + AsNumeric,
{
let g_coords: ArrayBase<ViewRepr<&'a f64>, Ix1> = g_coords.into();
let s_coords: ArrayBase<ViewRepr<&'a f64>, Ix1> = s_coords.into();
let gl = g_coords.len();
let sl = s_coords.len();
if gl != sl {
return Err(ImgalError::MismatchedArrayLengths {
a_arr_name: "g_coords",
a_arr_len: gl,
b_arr_name: "s_coords",
b_arr_len: sl,
});
}
let a = axis.unwrap_or(2);
if a >= 3 {
return Err(ImgalError::InvalidAxis {
axis_idx: a,
dim_len: 3,
});
}
let data: ArrayBase<ViewRepr<&'a T>, Ix3> = data.into();
let mut coords_set: HashSet<(u64, u64)> = HashSet::with_capacity(gl);
g_coords.iter().zip(s_coords.iter()).for_each(|(g, s)| {
coords_set.insert((g.to_bits(), s.to_bits()));
});
let mut shape = data.shape().to_vec();
shape.remove(a);
let mut map_arr = Array2::<bool>::default((shape[0], shape[1]));
let lanes = data.lanes(Axis(a));
let gs_mask_calc = |ln: ArrayView1<T>, p: &mut bool| {
let dg = ln[0].to_f64();
let ds = ln[1].to_f64();
if (!dg.is_nan() || !ds.is_nan() || dg != 0.0 && ds != 0.0)
&& coords_set.contains(&(dg.to_bits(), ds.to_bits()))
{
*p = true;
}
};
par!(threads,
seq_exp: Zip::from(lanes).and(map_arr.view_mut())
.for_each(&gs_mask_calc),
par_exp: Zip::from(lanes).and(map_arr.view_mut())
.par_for_each(&gs_mask_calc));
Ok(map_arr)
}
#[inline]
pub fn gs_modulation(g: f64, s: f64) -> f64 {
let g_sqr: f64 = g * g;
let s_sqr: f64 = s * s;
(g_sqr + s_sqr).sqrt()
}
#[inline]
pub fn gs_phase(g: f64, s: f64) -> f64 {
s.atan2(g)
}
#[inline]
pub fn monoexponential_coords(tau: f64, omega: f64) -> (f64, f64) {
let ot = omega * tau;
let denom = 1.0 + (ot * ot);
let g = 1.0 / denom;
let s = (omega * tau) / denom;
(g, s)
}