basic_dsp_vector/vector_types/general/
mapping.rs

1use super::super::{
2    ComplexNumberSpace, Domain, DspVec, ErrorReason, MetaData, RealNumberSpace, ScalarResult,
3    ToSlice, ToSliceMut,
4};
5use crate::inline_vector::InlineVector;
6use crate::multicore_support::*;
7use crate::numbers::*;
8use crate::{array_to_complex, array_to_complex_mut};
9
10/// Operations which allow to iterate over the vector and to derive results
11/// or to change the vector.
12pub trait MapInplaceOps<T>: Sized
13where
14    T: Sized,
15{
16    /// Transforms all vector elements using the function `map`.
17    fn map_inplace<'a, A, F>(&mut self, argument: A, map: &F)
18    where
19        A: Sync + Copy + Send,
20        F: Fn(T, usize, A) -> T + 'a + Sync;
21}
22
23/// Operations which allow to iterate over the vector and to derive results.
24pub trait MapAggregateOps<T, R>: Sized
25where
26    T: Sized,
27    R: Send,
28{
29    type Output;
30    /// Transforms all vector elements using the function `map` and then aggregates
31    /// all the results with `aggregate`. `aggregate` must be a commutativity and associativity;
32    /// that's because there is no guarantee that the numbers will
33    /// be aggregated in any deterministic order.
34    fn map_aggregate<'a, A, FMap, FAggr>(
35        &self,
36        argument: A,
37        map: &FMap,
38        aggregate: &FAggr,
39    ) -> Self::Output
40    where
41        A: Sync + Copy + Send,
42        FMap: Fn(T, usize, A) -> R + 'a + Sync,
43        FAggr: Fn(R, R) -> R + 'a + Sync + Send;
44}
45
46impl<S, T, N, D> MapInplaceOps<T> for DspVec<S, T, N, D>
47where
48    S: ToSliceMut<T>,
49    T: RealNumber,
50    N: RealNumberSpace,
51    D: Domain,
52{
53    fn map_inplace<'a, A, F>(&mut self, argument: A, map: &F)
54    where
55        A: Sync + Copy + Send,
56        F: Fn(T, usize, A) -> T + 'a + Sync,
57    {
58        if self.is_complex() {
59            self.mark_vector_as_invalid();
60            return;
61        }
62
63        let array = self.data.to_slice_mut();
64        let length = array.len();
65        Chunk::execute_with_range(
66            Complexity::Small,
67            &self.multicore_settings,
68            &mut array[0..length],
69            1,
70            argument,
71            move |array, range, argument| {
72                let mut i = range.start;
73                for num in array {
74                    *num = map(*num, i, argument);
75                    i += 1;
76                }
77            },
78        );
79    }
80}
81
82impl<S, T, N, D, R> MapAggregateOps<T, R> for DspVec<S, T, N, D>
83where
84    S: ToSlice<T>,
85    T: RealNumber,
86    N: RealNumberSpace,
87    D: Domain,
88    R: Send,
89{
90    type Output = ScalarResult<R>;
91
92    fn map_aggregate<'a, A, FMap, FAggr>(
93        &self,
94        argument: A,
95        map: &FMap,
96        aggregate: &FAggr,
97    ) -> ScalarResult<R>
98    where
99        A: Sync + Copy + Send,
100        FMap: Fn(T, usize, A) -> R + 'a + Sync,
101        FAggr: Fn(R, R) -> R + 'a + Sync + Send,
102    {
103        let mut result = {
104            if self.is_complex() {
105                return Err(ErrorReason::InputMustBeReal);
106            }
107
108            let array = self.data.to_slice();
109            let length = array.len();
110            if length == 0 {
111                return Err(ErrorReason::InputMustNotBeEmpty);
112            }
113            Chunk::map_on_array_chunks(
114                Complexity::Small,
115                &self.multicore_settings,
116                &array[0..length],
117                1,
118                argument,
119                move |array, range, argument| {
120                    let mut i = range.start;
121                    let mut sum: Option<R> = None;
122                    for num in array {
123                        let res = map(*num, i, argument);
124                        sum = match sum {
125                            None => Some(res),
126                            Some(s) => Some(aggregate(s, res)),
127                        };
128                        i += 1;
129                    }
130                    sum
131                },
132            )
133        };
134        // Would be nicer if we could use iter().fold(..) but we need
135        // the value of R and not just a reference so we can't user an iter
136        let mut only_valid_options = InlineVector::with_capacity(result.len());
137        for _ in 0..result.len() {
138            let elem = result.pop().unwrap();
139            match elem {
140                None => (),
141                Some(e) => only_valid_options.push(e),
142            };
143        }
144
145        if only_valid_options.is_empty() {
146            return Err(ErrorReason::InputMustNotBeEmpty);
147        }
148        let mut aggregated = only_valid_options.pop().unwrap();
149        for _ in 0..only_valid_options.len() {
150            aggregated = aggregate(aggregated, only_valid_options.pop().unwrap());
151        }
152        Ok(aggregated)
153    }
154}
155
156impl<S, T, N, D> MapInplaceOps<Complex<T>> for DspVec<S, T, N, D>
157where
158    S: ToSliceMut<T>,
159    T: RealNumber,
160    N: ComplexNumberSpace,
161    D: Domain,
162{
163    fn map_inplace<'a, A, F>(&mut self, argument: A, map: &F)
164    where
165        A: Sync + Copy + Send,
166        F: Fn(Complex<T>, usize, A) -> Complex<T> + 'a + Sync,
167    {
168        if !self.is_complex() {
169            self.mark_vector_as_invalid();
170            return;
171        }
172
173        let array = self.data.to_slice_mut();
174        let length = array.len();
175        Chunk::execute_with_range(
176            Complexity::Small,
177            &self.multicore_settings,
178            &mut array[0..length],
179            2,
180            argument,
181            move |array, range, argument| {
182                let mut i = range.start / 2;
183                let array = array_to_complex_mut(array);
184                for num in array {
185                    *num = map(*num, i, argument);
186                    i += 1;
187                }
188            },
189        );
190    }
191}
192
193impl<S, T, N, D, R> MapAggregateOps<Complex<T>, R> for DspVec<S, T, N, D>
194where
195    S: ToSlice<T>,
196    T: RealNumber,
197    N: ComplexNumberSpace,
198    D: Domain,
199    R: Send,
200{
201    type Output = ScalarResult<R>;
202
203    fn map_aggregate<'a, A, FMap, FAggr>(
204        &self,
205        argument: A,
206        map: &FMap,
207        aggregate: &FAggr,
208    ) -> ScalarResult<R>
209    where
210        A: Sync + Copy + Send,
211        FMap: Fn(Complex<T>, usize, A) -> R + 'a + Sync,
212        FAggr: Fn(R, R) -> R + 'a + Sync + Send,
213    {
214        let mut result = {
215            if !self.is_complex() {
216                return Err(ErrorReason::InputMustBeComplex);
217            }
218
219            let array = self.data.to_slice();
220            let length = array.len();
221            if length == 0 {
222                return Err(ErrorReason::InputMustNotBeEmpty);
223            }
224            Chunk::map_on_array_chunks(
225                Complexity::Small,
226                &self.multicore_settings,
227                &array[0..length],
228                2,
229                argument,
230                move |array, range, argument| {
231                    let array = array_to_complex(array);
232                    let mut i = range.start / 2;
233                    let mut sum: Option<R> = None;
234                    for num in array {
235                        let res = map(*num, i, argument);
236                        sum = match sum {
237                            None => Some(res),
238                            Some(s) => Some(aggregate(s, res)),
239                        };
240                        i += 1;
241                    }
242                    sum
243                },
244            )
245        };
246        // Would be nicer if we could use iter().fold(..) but we need
247        // the value of R and not just a reference so we can't user an iter
248        let mut only_valid_options = InlineVector::with_capacity(result.len());
249        for _ in 0..result.len() {
250            let elem = result.pop().unwrap();
251            match elem {
252                None => (),
253                Some(e) => only_valid_options.push(e),
254            };
255        }
256
257        if only_valid_options.is_empty() {
258            return Err(ErrorReason::InputMustNotBeEmpty);
259        }
260        let mut aggregated = only_valid_options.pop().unwrap();
261        for _ in 0..only_valid_options.len() {
262            aggregated = aggregate(aggregated, only_valid_options.pop().unwrap());
263        }
264        Ok(aggregated)
265    }
266}