use core::f64::consts::TAU;
use super::math_kernels as k;
use super::window_kernels as w;
use crate::{Array, Float, IntoArray, Num};
impl<F: Float> Array<F> {
pub fn sinc(&self) -> Array<F> {
self.par_map(k::sinc::<F>)
}
pub fn i0(&self) -> Array<F> {
self.par_map(k::i0::<F>)
}
pub fn deg2rad(&self) -> Array<F> {
self.par_map(k::deg2rad::<F>)
}
pub fn rad2deg(&self) -> Array<F> {
self.par_map(k::rad2deg::<F>)
}
pub fn rint(&self) -> Array<F> {
self.round()
}
pub fn fix(&self) -> Array<F> {
self.trunc()
}
pub fn fabs(&self) -> Array<F> {
self.abs()
}
pub fn positive(&self) -> Array<F> {
self.copy()
}
pub fn negative(&self) -> Array<F> {
-self
}
pub fn signbit(&self) -> Array<bool> {
self.par_map(k::signbit::<F>)
}
pub fn spacing(&self) -> Array<F> {
self.par_map(k::spacing::<F>)
}
pub fn modf(&self) -> (Array<F>, Array<F>) {
let (frac, int): (Vec<F>, Vec<F>) = self.iter().map(k::modf::<F>).unzip();
(
Array::from_vec(frac, self.shape()),
Array::from_vec(int, self.shape()),
)
}
pub fn frexp(&self) -> (Array<F>, Array<i32>) {
let (m, e): (Vec<F>, Vec<i32>) = self.iter().map(k::frexp::<F>).unzip();
(
Array::from_vec(m, self.shape()),
Array::from_vec(e, self.shape()),
)
}
pub fn nan_to_num(&self) -> Array<F> {
self.nan_to_num_with(F::ZERO, None, None)
}
pub fn nan_to_num_with(&self, nan: F, posinf: Option<F>, neginf: Option<F>) -> Array<F> {
self.par_map(|x| k::nan_to_num(x, nan, posinf, neginf))
}
pub fn unwrap(&self) -> Array<F> {
self.unwrap_with(None, -1, F::from_f64(TAU))
}
pub fn unwrap_with(&self, discont: Option<F>, axis: isize, period: F) -> Array<F> {
let nd = self.ndim();
assert!(
nd > 0,
"diff requires input that is at least one dimensional"
);
let ax = if axis < 0 { axis + nd as isize } else { axis };
assert!(
ax >= 0 && (ax as usize) < nd,
"axis {axis} is out of bounds for array of dimension {nd}"
);
let moved = self.moveaxis(ax, -1);
let n = moved.shape()[nd - 1];
let data = moved.to_vec();
let out = if n == 0 {
data
} else {
data.chunks(n)
.flat_map(|row| k::unwrap(row, discont, period))
.collect()
};
Array::from_vec(out, moved.shape()).moveaxis(-1, ax)
}
}
pub fn ediff1d<T: Num>(a: impl IntoArray<T>) -> Array<T> {
ediff1d_with(a, &[], &[])
}
pub fn ediff1d_with<T: Num>(a: impl IntoArray<T>, to_end: &[T], to_begin: &[T]) -> Array<T> {
Array::from(k::ediff1d(&a.into_array().to_vec(), to_end, to_begin))
}
pub fn angle<F: Float>(a: impl IntoArray<F>) -> Array<F> {
a.into_array().par_map(|x| k::angle(x, F::ZERO))
}
pub fn angle_deg<F: Float>(a: impl IntoArray<F>) -> Array<F> {
a.into_array().par_map(|x| k::angle_deg(x, F::ZERO))
}
pub fn logaddexp<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::logaddexp::<F>)
}
pub fn logaddexp2<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::logaddexp2::<F>)
}
pub fn fmod<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::fmod::<F>)
}
pub fn remainder<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::remainder::<F>)
}
pub fn floor_divide<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::floor_divide::<F>)
}
pub fn divmod<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> (Array<F>, Array<F>) {
let (a, b) = (a.into_array(), b.into_array());
let shape = a.common_shape(&b);
let (a, b) = (a.broadcast_to(&shape), b.broadcast_to(&shape));
let (q, r): (Vec<F>, Vec<F>) = a.iter().zip(b.iter()).map(|(x, y)| k::divmod(x, y)).unzip();
(Array::from_vec(q, &shape), Array::from_vec(r, &shape))
}
pub fn copysign<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::copysign::<F>)
}
pub fn heaviside<F: Float>(x: impl IntoArray<F>, h0: impl IntoArray<F>) -> Array<F> {
x.into_array().par_zip(h0, k::heaviside::<F>)
}
pub fn nextafter<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<F> {
a.into_array().par_zip(b, k::nextafter::<F>)
}
pub fn ldexp<F: Float>(a: impl IntoArray<F>, e: impl IntoArray<i32>) -> Array<F> {
a.into_array().par_zip(e, k::ldexp::<F>)
}
pub fn float_power<F: Float>(a: impl IntoArray<F>, b: impl IntoArray<F>) -> Array<f64> {
a.into_array().par_zip(b, k::float_power::<F>)
}
pub fn gcd(a: impl IntoArray<i64>, b: impl IntoArray<i64>) -> Array<i64> {
a.into_array().par_zip(b, k::gcd)
}
pub fn lcm(a: impl IntoArray<i64>, b: impl IntoArray<i64>) -> Array<i64> {
a.into_array().par_zip(b, k::lcm)
}
pub fn hanning(m: usize) -> Array<f64> {
Array::from(w::hanning(m))
}
pub fn hamming(m: usize) -> Array<f64> {
Array::from(w::hamming(m))
}
pub fn blackman(m: usize) -> Array<f64> {
Array::from(w::blackman(m))
}
pub fn bartlett(m: usize) -> Array<f64> {
Array::from(w::bartlett(m))
}
pub fn kaiser(m: usize, beta: f64) -> Array<f64> {
Array::from(w::kaiser(m, beta))
}
impl<F: Float> Array<F> {
pub fn sinc_inplace(&mut self) {
self.mapv_inplace_parallel(k::sinc::<F>);
}
pub fn into_sinc(mut self) -> Self {
self.sinc_inplace();
self
}
pub fn i0_inplace(&mut self) {
self.mapv_inplace_parallel(k::i0::<F>);
}
pub fn into_i0(mut self) -> Self {
self.i0_inplace();
self
}
pub fn deg2rad_inplace(&mut self) {
self.mapv_inplace_parallel(k::deg2rad::<F>);
}
pub fn into_deg2rad(mut self) -> Self {
self.deg2rad_inplace();
self
}
pub fn rad2deg_inplace(&mut self) {
self.mapv_inplace_parallel(k::rad2deg::<F>);
}
pub fn into_rad2deg(mut self) -> Self {
self.rad2deg_inplace();
self
}
pub fn rint_inplace(&mut self) {
self.mapv_inplace_parallel(F::round);
}
pub fn into_rint(mut self) -> Self {
self.rint_inplace();
self
}
pub fn fix_inplace(&mut self) {
self.mapv_inplace_parallel(F::trunc);
}
pub fn into_fix(mut self) -> Self {
self.fix_inplace();
self
}
pub fn fabs_inplace(&mut self) {
self.mapv_inplace_parallel(F::abs);
}
pub fn into_fabs(mut self) -> Self {
self.fabs_inplace();
self
}
pub fn positive_inplace(&mut self) {
self.mapv_inplace_parallel(|x| x);
}
pub fn into_positive(mut self) -> Self {
self.positive_inplace();
self
}
pub fn negative_inplace(&mut self) {
self.mapv_inplace_parallel(|x| -x);
}
pub fn into_negative(mut self) -> Self {
self.negative_inplace();
self
}
pub fn spacing_inplace(&mut self) {
self.mapv_inplace_parallel(k::spacing::<F>);
}
pub fn into_spacing(mut self) -> Self {
self.spacing_inplace();
self
}
pub fn nan_to_num_inplace(&mut self) {
self.mapv_inplace_parallel(|x| k::nan_to_num(x, F::ZERO, None, None));
}
pub fn into_nan_to_num(mut self) -> Self {
self.nan_to_num_inplace();
self
}
pub fn nan_to_num_with_inplace(&mut self, nan: F, posinf: Option<F>, neginf: Option<F>) {
self.mapv_inplace_parallel(|x| k::nan_to_num(x, nan, posinf, neginf));
}
pub fn into_nan_to_num_with(mut self, nan: F, posinf: Option<F>, neginf: Option<F>) -> Self {
self.nan_to_num_with_inplace(nan, posinf, neginf);
self
}
}