basic_dsp_vector/vector_types/
mod.rs

1use crate::multicore_support::{Chunk, Complexity, MultiCoreSettings};
2use crate::numbers::*;
3use crate::simd_extensions::*;
4use crate::{array_to_complex, array_to_complex_mut};
5use std;
6use std::cmp;
7use std::fmt;
8use std::mem;
9use std::ops::*;
10use std::result;
11
12mod requirements;
13pub use self::requirements::*;
14mod to_from_vec_conversions;
15pub use self::to_from_vec_conversions::*;
16mod support_core;
17pub use self::support_core::*;
18#[cfg(any(feature = "std", test))]
19mod support_std;
20#[cfg(any(feature = "std", test))]
21pub use self::support_std::*;
22#[cfg(feature = "std")]
23mod support_std_par;
24#[cfg(feature = "std")]
25pub use self::support_std_par::*;
26mod vec_impl_and_indexers;
27pub use self::vec_impl_and_indexers::*;
28mod complex;
29pub use self::complex::*;
30mod real;
31pub use self::real::*;
32mod time_freq;
33pub use self::time_freq::*;
34mod rededicate_and_relations;
35pub use self::rededicate_and_relations::*;
36mod checks_and_results;
37pub use self::checks_and_results::*;
38mod general;
39pub use self::general::*;
40mod buffer;
41pub use self::buffer::*;
42use super::meta;
43
44/// Result for operations which transform a type (most commonly the type is a vector).
45/// On success the transformed type is returned.
46/// On failure it contains an error reason and the original type with with invalid data
47/// which still can be used in order to avoid memory allocation.
48pub type TransRes<T> = result::Result<T, (ErrorReason, T)>;
49
50/// Void/nothing in case of success or a reason in case of an error.
51pub type VoidResult = result::Result<(), ErrorReason>;
52
53/// Scalar result or a reason in case of an error.
54pub type ScalarResult<T> = result::Result<T, ErrorReason>;
55
56/// The domain of a data vector
57#[derive(Copy, Clone, PartialEq, Debug)]
58pub enum DataDomain {
59    /// Time domain, the x-axis is in \[s\].
60    Time,
61    /// Frequency domain, the x-axis is in \[Hz\].
62    Frequency,
63}
64
65/// Number space (real or complex) information.
66pub trait NumberSpace: fmt::Debug + cmp::PartialEq + Clone {
67    fn is_complex(&self) -> bool;
68
69    /// For implementations which track meta data
70    /// at runtime this method may be implemented to transition
71    /// between different states. For all other implementations
72    /// they may leave this empty.
73    fn to_complex(&mut self);
74
75    /// See `to_complex` for more details.
76    fn to_real(&mut self);
77}
78
79/// Domain (time or frequency) information.
80pub trait Domain: fmt::Debug + cmp::PartialEq + Clone {
81    fn domain(&self) -> DataDomain;
82
83    /// See `to_complex` for some details.
84    fn to_freq(&mut self);
85
86    /// See `to_complex` for some details.
87    fn to_time(&mut self);
88}
89
90/// Trait for types containing real data.
91pub trait RealNumberSpace: NumberSpace {}
92
93/// Trait for types containing complex data.
94pub trait ComplexNumberSpace: NumberSpace {}
95
96/// Trait for types containing time domain data.
97pub trait TimeDomain: Domain {}
98
99/// Trait for types containing frequency domain data.
100pub trait FrequencyDomain: Domain {}
101
102/// Expresses at compile time that two classes could potentially represent the same number space or domain.
103pub trait PosEq<O> {}
104
105/// A 1xN (one times N elements) or Nx1 data vector as used for most digital signal processing
106/// (DSP) operations.
107///
108/// Vectors come in different flavors:
109///
110/// 1. Time or Frequency domain
111/// 2. Real or Complex numbers
112/// 3. 32bit or 64bit floating point numbers
113///
114/// The first two flavors define meta information about the vector and provide compile time
115/// information what operations are available with the given vector and how this will transform
116/// the vector. This makes sure that some invalid operations are already discovered at compile
117/// time. In case that this isn't desired or the information about the vector isn't known at
118/// compile time there are the generic [`DataVec32`](type.DataVec32.html) and
119/// [`DataVec64`](type.DataVec64.html) vectors available.
120///
121/// 32bit and 64bit flavors trade performance and memory consumption against accuracy.
122/// 32bit vectors are roughly two times faster than 64bit vectors for most operations.
123/// But remember that you should benchmark first before you give away accuracy for performance
124/// unless however you are sure that 32bit accuracy is certainly good enough.
125pub struct DspVec<S, T, N, D>
126where
127    S: ToSlice<T>,
128    T: RealNumber,
129    N: NumberSpace,
130    D: Domain,
131{
132    /// The underlying storage. `self.len()` should be called to find out how many
133    /// elements in `data` contain valid data.
134    pub data: S,
135    delta: T,
136    domain: D,
137    number_space: N,
138    valid_len: usize,
139    multicore_settings: MultiCoreSettings,
140}
141
142/// Holds meta data about a type.
143#[derive(Clone, Copy)]
144pub struct TypeMetaData<T, N, D> {
145    delta: T,
146    domain: D,
147    number_space: N,
148    multicore_settings: MultiCoreSettings,
149}
150
151impl<S, T, N, D> fmt::Debug for DspVec<S, T, N, D>
152where
153    S: ToSlice<T>,
154    T: RealNumber,
155    D: Domain,
156    N: NumberSpace,
157{
158    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159        write!(
160            f,
161            "DspVec {{ points: {}, domain: {:?}, number_space: {:?} }}",
162            self.valid_len, self.domain, self.number_space
163        )
164    }
165}
166
167/// Swaps the halves of two arrays. The `forward` paremeter
168/// specifies what should happen then the `data.len()` is odd.
169/// The function should always produce the same results as `fft_shift`
170/// and `ifft_shift` in GNU Octave.
171fn swap_array_halves<T>(data: &mut [T], forward: bool)
172where
173    T: Copy,
174{
175    let len = data.len();
176    if len % 2 == 0 {
177        let (lo, up) = data.split_at_mut(len / 2);
178        for (lo, up) in lo.iter_mut().zip(up.iter_mut()) {
179            mem::swap(lo, up);
180        }
181    } else {
182        let step = if forward { len / 2 } else { len / 2 + 1 };
183        let mut temp = data[0];
184        let mut pos = step;
185        for _ in 0..len {
186            let pos_new = (pos + step) % len;
187            mem::swap(&mut temp, &mut data[pos]);
188            pos = pos_new;
189        }
190    }
191}
192
193/// Creates an interleaved array slice from a complex array.
194fn complex_to_array<T>(complex: &[Complex<T>]) -> &[T]
195where
196    T: RealNumber,
197{
198    super::transmute_slice(complex)
199}
200
201/// Creates an interleaved array slice from a complex array.
202fn complex_to_array_mut<T>(complex: &mut [Complex<T>]) -> &mut [T]
203where
204    T: RealNumber,
205{
206    super::transmute_slice_mut(complex)
207}
208
209impl<S: ToSliceMut<T>, T: RealNumber> DspVec<S, T, meta::RealOrComplex, meta::TimeOrFreq> {
210    /// Indicates whether or not the operations on this vector have been successful.
211    /// Consider using the statically typed vector versions so that this check doesn't need to be
212    /// performed.
213    pub fn is_erroneous(&self) -> bool {
214        self.valid_len == 0 && self.delta.is_nan()
215    }
216}
217
218impl<S, T, N, D> DspVec<S, T, N, D>
219where
220    S: ToSliceMut<T>,
221    T: RealNumber,
222    N: NumberSpace,
223    D: Domain,
224{
225    /// Marks the data of the vector as erroneous
226    fn mark_vector_as_invalid(&mut self) {
227        self.valid_len = 0;
228        self.delta = T::nan();
229    }
230
231    /// Executes a real function.
232    #[inline]
233    fn pure_real_operation<A, F>(&mut self, op: F, argument: A, complexity: Complexity)
234    where
235        A: Sync + Copy + Send,
236        F: Fn(T, A) -> T + 'static + Sync,
237    {
238        {
239            let len = self.valid_len;
240            let array = self.data.to_slice_mut();
241            Chunk::execute_partial(
242                complexity,
243                &self.multicore_settings,
244                &mut array[0..len],
245                1,
246                argument,
247                move |array, argument| {
248                    for num in array {
249                        *num = op(*num, argument);
250                    }
251                },
252            );
253        }
254    }
255
256    /// Executes a complex function.
257    #[inline]
258    fn pure_complex_operation<A, F>(&mut self, op: F, argument: A, complexity: Complexity)
259    where
260        A: Sync + Copy + Send,
261        F: Fn(Complex<T>, A) -> Complex<T> + 'static + Sync,
262    {
263        {
264            let len = self.valid_len;
265            let array = self.data.to_slice_mut();
266            Chunk::execute_partial(
267                complexity,
268                &self.multicore_settings,
269                &mut array[0..len],
270                2,
271                argument,
272                move |array, argument| {
273                    let array = array_to_complex_mut(array);
274                    for num in array {
275                        *num = op(*num, argument);
276                    }
277                },
278            );
279        }
280    }
281
282    #[inline]
283    fn simd_real_operationf<Reg: SimdGeneric<T>, F, G>(
284        &mut self,
285        reg: RegType<Reg>,
286        simd_op: F,
287        scalar_op: G,
288        argument: T,
289        complexity: Complexity,
290    ) where
291        F: Fn(Reg, Reg) -> Reg + 'static + Sync,
292        G: Fn(T, Reg) -> T + 'static + Sync,
293    {
294        self.simd_real_operation(reg, simd_op, scalar_op, Reg::splat(argument), complexity);
295    }
296
297    /// Executes a real function with SIMD optimization.
298    #[inline]
299    fn simd_real_operation<Reg: SimdGeneric<T>, A, F, G>(
300        &mut self,
301        _: RegType<Reg>,
302        simd_op: F,
303        scalar_op: G,
304        argument: A,
305        complexity: Complexity,
306    ) where
307        A: Sync + Copy + Send,
308        F: Fn(Reg, A) -> Reg + 'static + Sync,
309        G: Fn(T, A) -> T + 'static + Sync,
310    {
311        {
312            let data_length = self.valid_len;
313            let array = self.data.to_slice_mut();
314            let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
315            Chunk::execute_partial(
316                complexity,
317                &self.multicore_settings,
318                partition.center_mut(array),
319                Reg::LEN,
320                argument,
321                move |array, argument| {
322                    let array = Reg::array_to_regs_mut(array);
323                    for reg in array {
324                        *reg = simd_op(*reg, argument);
325                    }
326                },
327            );
328
329            for num in partition.edge_iter_mut(&mut array[0..data_length]) {
330                *num = scalar_op(*num, argument);
331            }
332        }
333    }
334
335    #[inline]
336    fn simd_complex_operationf<Reg: SimdGeneric<T>, F, G>(
337        &mut self,
338        reg: RegType<Reg>,
339        simd_op: F,
340        scalar_op: G,
341        argument: Complex<T>,
342        complexity: Complexity,
343    ) where
344        F: Fn(Reg, Reg) -> Reg + 'static + Sync,
345        G: Fn(Complex<T>, Reg) -> Complex<T> + 'static + Sync,
346    {
347        self.simd_complex_operation(
348            reg,
349            simd_op,
350            scalar_op,
351            Reg::from_complex(argument),
352            complexity,
353        )
354    }
355
356    /// Executes a complex function with SIMD optimization.
357    #[inline]
358    fn simd_complex_operation<Reg: SimdGeneric<T>, A, F, G>(
359        &mut self,
360        _: RegType<Reg>,
361        simd_op: F,
362        scalar_op: G,
363        argument: A,
364        complexity: Complexity,
365    ) where
366        A: Sync + Copy + Send,
367        F: Fn(Reg, A) -> Reg + 'static + Sync,
368        G: Fn(Complex<T>, A) -> Complex<T> + 'static + Sync,
369    {
370        {
371            let data_length = self.valid_len;
372            let array = self.data.to_slice_mut();
373            let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
374            Chunk::execute_partial(
375                complexity,
376                &self.multicore_settings,
377                partition.center_mut(array),
378                Reg::LEN,
379                argument,
380                move |array, argument| {
381                    let array = Reg::array_to_regs_mut(array);
382                    for reg in array {
383                        *reg = simd_op(*reg, argument);
384                    }
385                },
386            );
387
388            for num in partition.cedge_iter_mut(array_to_complex_mut(&mut array[0..data_length])) {
389                *num = scalar_op(*num, argument);
390            }
391        }
392    }
393
394    /// Executes a function which converts a complex array into a real array.
395    #[inline]
396    fn pure_complex_to_real_operation<A, F, B>(
397        &mut self,
398        buffer: &mut B,
399        op: F,
400        argument: A,
401        complexity: Complexity,
402    ) where
403        A: Sync + Copy + Send,
404        F: Fn(Complex<T>, A) -> T + 'static + Sync,
405        B: for<'a> Buffer<'a, S, T>,
406    {
407        {
408            let data_length = self.len();
409            let mut result = buffer.borrow(data_length / 2);
410            {
411                let array = self.data.to_slice_mut();
412                let temp = result.to_slice_mut();
413                Chunk::from_src_to_dest(
414                    complexity,
415                    &self.multicore_settings,
416                    &array[0..data_length],
417                    2,
418                    &mut temp[0..data_length / 2],
419                    1,
420                    argument,
421                    move |array, range, target, argument| {
422                        let array = array_to_complex(&array[range.start..range.end]);
423                        for pair in array.iter().zip(target) {
424                            let (src, dest) = pair;
425                            *dest = op(*src, argument);
426                        }
427                    },
428                );
429                self.valid_len = data_length / 2;
430            }
431            result.trade(&mut self.data);
432        }
433    }
434
435    /// Executes a function which converts a complex array into a real array. Conversion is applied in-place.
436    #[inline]
437    fn pure_complex_to_real_operation_inplace<A, F>(&mut self, op: F, argument: A)
438    where
439        A: Sync + Copy + Send,
440        F: Fn(Complex<T>, A) -> T + 'static + Sync,
441    {
442        {
443            let data_length = self.len();
444            let array = self.data.to_slice_mut();
445            for i in 0..data_length / 2 {
446                let input = Complex::new(array[2 * i], array[2 * i + 1]);
447                array[i] = op(input, argument);
448            }
449
450            self.valid_len /= 2;
451        }
452    }
453
454    /// Executes a function which converts a complex array into a real array.
455    #[inline]
456    fn simd_complex_to_real_operation<Reg: SimdGeneric<T>, A, F, G, B>(
457        &mut self,
458        _: RegType<Reg>,
459        buffer: &mut B,
460        simd_op: F,
461        scalar_op: G,
462        argument: A,
463        complexity: Complexity,
464    ) where
465        A: Sync + Copy + Send,
466        F: Fn(Reg, A) -> Reg + 'static + Sync,
467        G: Fn(Complex<T>, A) -> T + 'static + Sync,
468        B: for<'a> Buffer<'a, S, T>,
469    {
470        let data_length = self.len();
471        let mut result = buffer.borrow(data_length / 2);
472        {
473            let array = self.data.to_slice_mut();
474            let temp = result.to_slice_mut();
475            let partition = Reg::calc_data_alignment_reqs(&array[0..data_length]);
476            Chunk::from_src_to_dest(
477                complexity,
478                &self.multicore_settings,
479                partition.center(&array),
480                Reg::LEN,
481                partition.rcenter_mut(temp),
482                Reg::LEN / 2,
483                argument,
484                move |array, range, target, argument| {
485                    let array = Reg::array_to_regs(&array[range.start..range.end]);
486                    let mut j = 0;
487                    for reg in array {
488                        let result = simd_op(*reg, argument);
489                        result.store_real(target, j);
490                        j += Reg::LEN / 2;
491                    }
492                },
493            );
494
495            let array = array_to_complex(&array[0..data_length]);
496            for (src, dest) in partition
497                .cedge_iter(array)
498                .zip(partition.redge_iter_mut(temp))
499            {
500                *dest = scalar_op(*src, argument);
501            }
502
503            self.valid_len /= 2;
504        }
505        result.trade(&mut self.data);
506    }
507
508    /// Forwards calls to `swap_array_halves`.
509    #[inline]
510    fn swap_halves_priv(&mut self, forward: bool) {
511        let len = self.len();
512        if len == 0 {
513            return;
514        }
515
516        if self.is_complex() {
517            let data = self.data.to_slice_mut();
518            let data = array_to_complex_mut(&mut data[0..len]);
519            swap_array_halves(data, forward);
520        } else {
521            let data = self.data.to_slice_mut();
522            swap_array_halves(&mut data[0..len], forward);
523        }
524    }
525
526    /// Multiplies the vector with a window function.
527    #[inline]
528    fn multiply_window_priv<TT, CMut, FA, F>(
529        &mut self,
530        is_symmetric: bool,
531        convert_mut: CMut,
532        function_arg: FA,
533        fun: F,
534    ) where
535        CMut: Fn(&mut [T]) -> &mut [TT],
536        FA: Copy + Sync + Send,
537        F: Fn(FA, usize, usize) -> TT + 'static + Sync,
538        TT: Zero + Mul<Output = TT> + Copy + Send + Sync + From<T>,
539    {
540        if !is_symmetric {
541            {
542                let len = self.len();
543                let points = self.points();
544                let data = self.data.to_slice_mut();
545                let converted = convert_mut(&mut data[0..len]);
546                Chunk::execute_with_range(
547                    Complexity::Medium,
548                    &self.multicore_settings,
549                    converted,
550                    1,
551                    function_arg,
552                    move |array, range, arg| {
553                        let mut j = range.start;
554                        for num in array {
555                            *num = (*num) * fun(arg, j, points);
556                            j += 1;
557                        }
558                    },
559                );
560            }
561        } else {
562            {
563                let len = self.len();
564                let points = self.points();
565                let data = self.data.to_slice_mut();
566                let converted = convert_mut(&mut data[0..len]);
567                Chunk::execute_sym_pairs_with_range(
568                    Complexity::Medium,
569                    &self.multicore_settings,
570                    converted,
571                    1,
572                    function_arg,
573                    move |array1, range, array2, _, arg| {
574                        assert!(array1.len() >= array2.len());
575                        let mut j = range.start;
576                        let len1 = array1.len();
577                        let len_diff = len1 - array2.len();
578                        {
579                            let iter1 = array1.iter_mut();
580                            let iter2 = array2.iter_mut().rev();
581                            for (num1, num2) in iter1.zip(iter2) {
582                                let arg = fun(arg, j, points);
583                                *num1 = (*num1) * arg;
584                                *num2 = (*num2) * arg;
585                                j += 1;
586                            }
587                        }
588                        for num1 in &mut array1[len1 - len_diff..len1] {
589                            let arg = fun(arg, j, points);
590                            *num1 = (*num1) * arg;
591                            j += 1;
592                        }
593                    },
594                );
595            }
596        }
597    }
598}
599
600/// Buffer borrow type for `NoTradeBufferBurrow`.
601pub struct NoTradeBufferBurrow<'a, T: RealNumber + 'a> {
602    data: &'a mut [T],
603}
604
605impl<'a, T: RealNumber + 'a> ToSlice<T> for NoTradeBufferBurrow<'a, T> {
606    fn to_slice(&self) -> &[T] {
607        self.data.to_slice()
608    }
609
610    fn len(&self) -> usize {
611        self.data.len()
612    }
613
614    fn is_empty(&self) -> bool {
615        self.data.is_empty()
616    }
617
618    fn alloc_len(&self) -> usize {
619        self.data.alloc_len()
620    }
621
622    fn try_resize(&mut self, len: usize) -> VoidResult {
623        self.data.try_resize(len)
624    }
625}
626
627impl<'a, T: RealNumber + 'a> ToSliceMut<T> for NoTradeBufferBurrow<'a, T> {
628    fn to_slice_mut(&mut self) -> &mut [T] {
629        self.data.to_slice_mut()
630    }
631}
632
633impl<'a, S: ToSliceMut<T>, T: RealNumber> BufferBorrow<S, T> for NoTradeBufferBurrow<'a, T> {
634    fn trade(self, _: &mut S) {
635        // No trade
636    }
637}
638
639/// For internal use only. A buffer which doesn't implement the `swap` routine. Swapping is a no-op in this
640/// implementation. This can be useful in cases where an implementation will do the swap step on its own.
641struct NoTradeBuffer<B, S, T>
642where
643    B: BufferBorrow<S, T>,
644    S: ToSliceMut<T>,
645    T: RealNumber,
646{
647    data: B,
648    storage_type: std::marker::PhantomData<S>,
649    data_type: std::marker::PhantomData<T>,
650}
651
652impl<B, S, T> NoTradeBuffer<B, S, T>
653where
654    B: BufferBorrow<S, T>,
655    S: ToSliceMut<T>,
656    T: RealNumber,
657{
658    /// Creates a new buffer from a storage type. The buffer will internally hold
659    /// its storage for it's complete life time.
660    pub fn new(storage: B) -> NoTradeBuffer<B, S, T> {
661        NoTradeBuffer {
662            data: storage,
663            storage_type: std::marker::PhantomData,
664            data_type: std::marker::PhantomData,
665        }
666    }
667}
668
669impl<'a, B, S, T> Buffer<'a, &mut [T], T> for NoTradeBuffer<B, S, T>
670where
671    B: BufferBorrow<S, T>,
672    S: ToSliceMut<T>,
673    T: RealNumber + 'a,
674{
675    type Borrow = NoTradeBufferBurrow<'a, T>;
676
677    fn borrow(&'a mut self, len: usize) -> Self::Borrow {
678        self.data
679            .try_resize(len)
680            .expect("NoTradeBuffer: Out of memory");
681        NoTradeBufferBurrow {
682            data: &mut self.data.to_slice_mut()[0..len],
683        }
684    }
685
686    fn alloc_len(&self) -> usize {
687        self.data.alloc_len()
688    }
689}
690
691#[cfg(test)]
692mod tests {
693    use super::swap_array_halves;
694
695    #[test]
696    fn swap_halves_even_test() {
697        let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
698        swap_array_halves(&mut v, false);
699        assert_eq!(&v[..], &[5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0]);
700    }
701
702    #[test]
703    fn swap_halves_odd_foward_test() {
704        let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
705        swap_array_halves(&mut v, true);
706        assert_eq!(&v[..], &[6.0, 7.0, 8.0, 9.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
707    }
708
709    #[test]
710    fn swap_halves_odd_inverse_test() {
711        let mut v = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
712        swap_array_halves(&mut v, false);
713        assert_eq!(&v[..], &[5.0, 6.0, 7.0, 8.0, 9.0, 1.0, 2.0, 3.0, 4.0]);
714    }
715}