use super::super::{
Buffer, ComplexNumberSpace, Domain, DspVec, ErrorReason, GetMetaData, MetaData, NumberSpace,
PosEq, RealNumberSpace, RededicateForceOps, Resize, ToRealResult, ToSlice, ToSliceMut, Vector,
VoidResult,
};
use crate::array_to_complex;
use crate::multicore_support::*;
use crate::numbers::*;
use crate::simd_extensions::*;
use std::ops::*;
pub trait ComplexToRealTransformsOps<T>: ToRealResult
where
T: RealNumber,
{
fn magnitude(self) -> Self::RealResult;
fn magnitude_squared(self) -> Self::RealResult;
fn to_real(self) -> Self::RealResult;
fn to_imag(self) -> Self::RealResult;
fn phase(self) -> Self::RealResult;
}
pub trait ComplexToRealTransformsOpsBuffered<S, T>: ToRealResult
where
S: ToSliceMut<T>,
T: RealNumber,
{
fn magnitude_b<B>(self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>;
fn magnitude_squared_b<B>(self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>;
fn to_real_b<B>(self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>;
fn to_imag_b<B>(self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>;
fn phase_b<B>(self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>;
}
pub trait ComplexToRealGetterOps<A, T, N, D>
where
T: RealNumber,
N: NumberSpace,
D: Domain,
A: GetMetaData<T, N, D>,
{
fn get_real(&self, destination: &mut A);
fn get_imag(&self, destination: &mut A);
fn get_magnitude(&self, destination: &mut A);
fn get_magnitude_squared(&self, destination: &mut A);
fn get_phase(&self, destination: &mut A);
fn get_real_imag(&self, real: &mut A, imag: &mut A);
fn get_mag_phase(&self, mag: &mut A, phase: &mut A);
}
pub trait ComplexToRealSetterOps<A, T, N, D>
where
T: RealNumber,
N: NumberSpace,
D: Domain,
A: GetMetaData<T, N, D>,
{
fn set_real_imag(&mut self, real: &A, imag: &A) -> VoidResult;
fn set_mag_phase(&mut self, mag: &A, phase: &A) -> VoidResult;
}
macro_rules! assert_complex {
($self_: ident) => {
if !$self_.is_complex() {
$self_.number_space.to_real();
$self_.mark_vector_as_invalid();
return Self::RealResult::rededicate_from_force($self_);
}
};
}
impl<S, T, N, D> ComplexToRealTransformsOps<T> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToRealResult,
<DspVec<S, T, N, D> as ToRealResult>::RealResult: RededicateForceOps<DspVec<S, T, N, D>>,
S: ToSliceMut<T>,
T: RealNumber,
N: ComplexNumberSpace,
D: Domain,
{
fn magnitude(mut self) -> Self::RealResult {
assert_complex!(self);
self.pure_complex_to_real_operation_inplace(|x, _arg| x.norm(), ());
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn magnitude_squared(mut self) -> Self::RealResult {
assert_complex!(self);
self.pure_complex_to_real_operation_inplace(|x, _arg| x.re * x.re + x.im * x.im, ());
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn to_real(mut self) -> Self::RealResult {
assert_complex!(self);
self.pure_complex_to_real_operation_inplace(|x, _arg| x.re, ());
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn to_imag(mut self) -> Self::RealResult {
assert_complex!(self);
self.pure_complex_to_real_operation_inplace(|x, _arg| x.im, ());
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn phase(mut self) -> Self::RealResult {
assert_complex!(self);
self.pure_complex_to_real_operation_inplace(|x, _arg| x.arg(), ());
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
}
impl<S, T, N, D> ComplexToRealTransformsOpsBuffered<S, T> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToRealResult,
<DspVec<S, T, N, D> as ToRealResult>::RealResult: RededicateForceOps<DspVec<S, T, N, D>>,
S: ToSliceMut<T>,
T: RealNumber,
N: ComplexNumberSpace,
D: Domain,
{
fn magnitude_b<B>(mut self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>,
{
assert_complex!(self);
sel_reg!(self.simd_complex_to_real_operation::<T>(
buffer,
|x, _arg| x.complex_abs(),
|x, _arg| x.norm(),
(),
Complexity::Small
));
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn magnitude_squared_b<B>(mut self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>,
{
assert_complex!(self);
sel_reg!(self.simd_complex_to_real_operation::<T>(
buffer,
|x, _arg| x.complex_abs_squared(),
|x, _arg| x.re * x.re + x.im * x.im,
(),
Complexity::Small
));
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn to_real_b<B>(mut self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>,
{
assert_complex!(self);
self.pure_complex_to_real_operation(buffer, |x, _arg| x.re, (), Complexity::Small);
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn to_imag_b<B>(mut self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>,
{
assert_complex!(self);
self.pure_complex_to_real_operation(buffer, |x, _arg| x.im, (), Complexity::Small);
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
fn phase_b<B>(mut self, buffer: &mut B) -> Self::RealResult
where
B: for<'a> Buffer<'a, S, T>,
{
assert_complex!(self);
self.pure_complex_to_real_operation(buffer, |x, _arg| x.arg(), (), Complexity::Small);
self.number_space.to_real();
Self::RealResult::rededicate_from_force(self)
}
}
impl<S, T, N, D> DspVec<S, T, N, D>
where
S: ToSlice<T>,
T: RealNumber,
N: ComplexNumberSpace,
D: Domain,
{
#[inline]
fn pure_complex_into_real_target_operation<A, F, V>(
&self,
destination: &mut V,
op: F,
argument: A,
complexity: Complexity,
) where
A: Sync + Copy + Send,
F: Fn(Complex<T>, A) -> T + 'static + Sync,
V: Vector<T> + Index<Range<usize>, Output = [T]> + IndexMut<Range<usize>>,
{
let len = self.len();
destination
.resize(len / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");
destination.set_delta(self.delta);
let array = &mut destination[0..len / 2];
let source = &self.data.to_slice();
Chunk::from_src_to_dest(
complexity,
&self.multicore_settings,
&source[0..len],
2,
array,
1,
argument,
move |original, range, target, argument| {
let mut i = range.start;
let mut j = 0;
while j < target.len() {
let complex = Complex::<T>::new(original[i], original[i + 1]);
target[j] = op(complex, argument);
i += 2;
j += 1;
}
},
);
}
#[inline]
fn simd_complex_into_real_target_operation<Reg: SimdGeneric<T>, FSimd, F, V>(
&self,
_: RegType<Reg>,
destination: &mut V,
op_simd: FSimd,
op: F,
complexity: Complexity,
) where
F: Fn(Complex<T>) -> T + 'static + Sync,
FSimd: Fn(Reg) -> Reg + 'static + Sync,
V: Vector<T> + Index<Range<usize>, Output = [T]> + IndexMut<Range<usize>>,
{
let data_length = self.len();
destination
.resize(data_length / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");;
destination.set_delta(self.delta);
let temp = &mut destination[0..data_length / 2];
let array = &self.data.to_slice();
let partition = Reg::calc_data_alignment_reqs(array);
Chunk::from_src_to_dest(
complexity,
&self.multicore_settings,
partition.center(array),
Reg::LEN,
partition.rcenter_mut(temp),
Reg::LEN / 2,
(),
move |array, range, target, _arg| {
let mut i = 0;
let array = Reg::array_to_regs(&array[range]);
for n in array {
let result = op_simd(*n);
result.store_half(target, i);
i += Reg::LEN / 2;
}
},
);
for (dest, src) in partition
.redge_iter_mut(temp)
.zip(partition.cedge_iter(array_to_complex(array)))
{
*dest = op(*src);
}
}
}
macro_rules! assert_self_complex_and_target_real {
($self_: ident, $target: ident) => {
if !$self_.is_complex() || $target.is_complex() {
$target.resize(0).unwrap();
return;
}
};
}
macro_rules! assert_self_complex_and_targets_real {
($self_: ident, $real: ident, $imag: ident) => {
if !$self_.is_complex() || $real.is_complex() || $imag.is_complex() {
$real.resize(0).unwrap();
$imag.resize(0).unwrap();
return;
}
};
}
impl<S, T, N, NR, D, O, DO> ComplexToRealGetterOps<O, T, NR, DO> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToRealResult,
O: Vector<T>
+ GetMetaData<T, NR, DO>
+ Index<Range<usize>, Output = [T]>
+ IndexMut<Range<usize>>,
S: ToSlice<T>,
T: RealNumber,
N: ComplexNumberSpace,
NR: RealNumberSpace,
D: Domain,
DO: PosEq<D> + Domain,
{
fn get_real(&self, destination: &mut O) {
assert_self_complex_and_target_real!(self, destination);
destination
.resize(self.len())
.expect("Target is real and thus all values are valid");
self.pure_complex_into_real_target_operation(
destination,
|x, _arg| x.re,
(),
Complexity::Small,
);
}
fn get_imag(&self, destination: &mut O) {
assert_self_complex_and_target_real!(self, destination);
destination
.resize(self.len())
.expect("Target is real and thus all values are valid");
self.pure_complex_into_real_target_operation(
destination,
|x, _arg| x.im,
(),
Complexity::Small,
);
}
fn get_magnitude(&self, destination: &mut O) {
assert_self_complex_and_target_real!(self, destination);
destination
.resize(self.len())
.expect("Target is real and thus all values are valid");
sel_reg!(self.simd_complex_into_real_target_operation::<T>(
destination,
|x| x.complex_abs(),
|x| x.norm(),
Complexity::Small
));
}
fn get_magnitude_squared(&self, destination: &mut O) {
assert_self_complex_and_target_real!(self, destination);
destination
.resize(self.len())
.expect("Target is real and thus all values are valid");
sel_reg!(self.simd_complex_into_real_target_operation::<T>(
destination,
|x| x.complex_abs_squared(),
|x| x.re * x.re + x.im * x.im,
Complexity::Small
));
}
fn get_phase(&self, destination: &mut O) {
assert_self_complex_and_target_real!(self, destination);
destination
.resize(self.len())
.expect("Target is real and thus all values are valid");
self.pure_complex_into_real_target_operation(
destination,
|x, _arg| x.arg(),
(),
Complexity::Small,
)
}
fn get_real_imag(&self, real: &mut O, imag: &mut O) {
assert_self_complex_and_targets_real!(self, real, imag);
let data_length = self.len();
real.resize(data_length / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");
imag.resize(data_length / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");
let real = &mut real[0..data_length / 2];
let imag = &mut imag[0..data_length / 2];
let data = self.data.to_slice();
for (i, n) in (&data[0..data_length]).iter().enumerate() {
if i % 2 == 0 {
real[i / 2] = *n;
} else {
imag[i / 2] = *n;
}
}
}
fn get_mag_phase(&self, mag: &mut O, phase: &mut O) {
assert_self_complex_and_targets_real!(self, mag, phase);
let data_length = self.len();
mag.resize(data_length / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");
phase
.resize(data_length / 2)
.expect("Target should be real and thus all values for len / 2 should be valid");
let mag = &mut mag[0..data_length / 2];
let phase = &mut phase[0..data_length / 2];
let data = self.data.to_slice();
let mut i = 0;
while i < data_length {
let c = Complex::<T>::new(data[i], data[i + 1]);
let (m, p) = c.to_polar();
mag[i / 2] = m;
phase[i / 2] = p;
i += 2;
}
}
}
impl<S, T, N, NR, D, O, DO> ComplexToRealSetterOps<O, T, NR, DO> for DspVec<S, T, N, D>
where
DspVec<S, T, N, D>: ToRealResult,
O: Index<Range<usize>, Output = [T]> + Vector<T> + GetMetaData<T, NR, DO>,
S: ToSliceMut<T> + Resize,
T: RealNumber,
N: ComplexNumberSpace,
NR: RealNumberSpace,
D: Domain,
DO: PosEq<D> + Domain,
{
fn set_real_imag(&mut self, real: &O, imag: &O) -> VoidResult {
{
if real.len() != imag.len() {
return Err(ErrorReason::InvalidArgumentLength);
}
let data_length = real.len() + imag.len();
self.data.resize(data_length);
self.valid_len = data_length;
let data = self.data.to_slice_mut();
let real = &real[0..real.len()];
let imag = &imag[0..imag.len()];
for (i, n) in (&mut data[0..data_length]).iter_mut().enumerate() {
if i % 2 == 0 {
*n = real[i / 2];
} else {
*n = imag[i / 2];
}
}
}
Ok(())
}
fn set_mag_phase(&mut self, mag: &O, phase: &O) -> VoidResult {
{
if mag.len() != phase.len() {
return Err(ErrorReason::InvalidArgumentLength);
}
let data_length = mag.len() + phase.len();
self.data.resize(data_length);
self.valid_len = data_length;
let data = self.data.to_slice_mut();
let mag = &mag[0..mag.len()];
let phase = &phase[0..phase.len()];
let mut i = 0;
while i < data_length {
let c = Complex::<T>::from_polar(&mag[i / 2], &phase[i / 2]);
data[i] = c.re;
data[i + 1] = c.im;
i += 2;
}
}
Ok(())
}
}