Chris@49
|
1 // Copyright (C) 2013 Conrad Sanderson
|
Chris@49
|
2 // Copyright (C) 2013 NICTA (www.nicta.com.au)
|
Chris@49
|
3 //
|
Chris@49
|
4 // This Source Code Form is subject to the terms of the Mozilla Public
|
Chris@49
|
5 // License, v. 2.0. If a copy of the MPL was not distributed with this
|
Chris@49
|
6 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
Chris@49
|
7
|
Chris@49
|
8
|
Chris@49
|
9
|
Chris@49
|
10 //! \addtogroup op_fft
|
Chris@49
|
11 //! @{
|
Chris@49
|
12
|
Chris@49
|
13
|
Chris@49
|
14
|
Chris@49
|
15 //
|
Chris@49
|
16 // op_fft_real
|
Chris@49
|
17
|
Chris@49
|
18
|
Chris@49
|
19
|
Chris@49
|
20 template<typename T1>
|
Chris@49
|
21 inline
|
Chris@49
|
22 void
|
Chris@49
|
23 op_fft_real::apply( Mat< std::complex<typename T1::pod_type> >& out, const mtOp<std::complex<typename T1::pod_type>,T1,op_fft_real>& in )
|
Chris@49
|
24 {
|
Chris@49
|
25 arma_extra_debug_sigprint();
|
Chris@49
|
26
|
Chris@49
|
27 typedef typename T1::pod_type in_eT;
|
Chris@49
|
28 typedef typename std::complex<in_eT> out_eT;
|
Chris@49
|
29
|
Chris@49
|
30 const Proxy<T1> P(in.m);
|
Chris@49
|
31
|
Chris@49
|
32 const uword n_rows = P.get_n_rows();
|
Chris@49
|
33 const uword n_cols = P.get_n_cols();
|
Chris@49
|
34 const uword n_elem = P.get_n_elem();
|
Chris@49
|
35
|
Chris@49
|
36 const bool is_vec = ( (n_rows == 1) || (n_cols == 1) );
|
Chris@49
|
37
|
Chris@49
|
38 const uword N_orig = (is_vec) ? n_elem : n_rows;
|
Chris@49
|
39 const uword N_user = (in.aux_uword_b == 0) ? in.aux_uword_a : N_orig;
|
Chris@49
|
40
|
Chris@49
|
41 fft_engine<out_eT,false> worker(N_user);
|
Chris@49
|
42
|
Chris@49
|
43 // no need to worry about aliasing, as we're going from a real object to complex complex, which by definition cannot alias
|
Chris@49
|
44
|
Chris@49
|
45 if(is_vec)
|
Chris@49
|
46 {
|
Chris@49
|
47 (n_cols == 1) ? out.set_size(N_user, 1) : out.set_size(1, N_user);
|
Chris@49
|
48
|
Chris@49
|
49 if( (out.n_elem == 0) || (N_orig == 0) )
|
Chris@49
|
50 {
|
Chris@49
|
51 out.zeros();
|
Chris@49
|
52 return;
|
Chris@49
|
53 }
|
Chris@49
|
54
|
Chris@49
|
55 if( (N_user == 1) && (N_orig >= 1) )
|
Chris@49
|
56 {
|
Chris@49
|
57 out[0] = out_eT( P[0] );
|
Chris@49
|
58 return;
|
Chris@49
|
59 }
|
Chris@49
|
60
|
Chris@49
|
61 podarray<out_eT> data(N_user);
|
Chris@49
|
62
|
Chris@49
|
63 out_eT* data_mem = data.memptr();
|
Chris@49
|
64
|
Chris@49
|
65 if(N_user > N_orig) { arrayops::inplace_set( &data_mem[N_orig], out_eT(0), (N_user - N_orig) ); }
|
Chris@49
|
66
|
Chris@49
|
67 const uword N = (std::min)(N_user, N_orig);
|
Chris@49
|
68
|
Chris@49
|
69 if(Proxy<T1>::prefer_at_accessor == false)
|
Chris@49
|
70 {
|
Chris@49
|
71 typename Proxy<T1>::ea_type X = P.get_ea();
|
Chris@49
|
72
|
Chris@49
|
73 for(uword i=0; i < N; ++i) { data_mem[i] = out_eT( X[i], in_eT(0) ); }
|
Chris@49
|
74 }
|
Chris@49
|
75 else
|
Chris@49
|
76 {
|
Chris@49
|
77 if(n_cols == 1)
|
Chris@49
|
78 {
|
Chris@49
|
79 for(uword i=0; i < N; ++i) { data_mem[i] = out_eT( P.at(i,0), in_eT(0) ); }
|
Chris@49
|
80 }
|
Chris@49
|
81 else
|
Chris@49
|
82 {
|
Chris@49
|
83 for(uword i=0; i < N; ++i) { data_mem[i] = out_eT( P.at(0,i), in_eT(0) ); }
|
Chris@49
|
84 }
|
Chris@49
|
85 }
|
Chris@49
|
86
|
Chris@49
|
87 worker.run( out.memptr(), data_mem );
|
Chris@49
|
88 }
|
Chris@49
|
89 else
|
Chris@49
|
90 {
|
Chris@49
|
91 // process each column seperately
|
Chris@49
|
92
|
Chris@49
|
93 out.set_size(N_user, n_cols);
|
Chris@49
|
94
|
Chris@49
|
95 if( (out.n_elem == 0) || (N_orig == 0) )
|
Chris@49
|
96 {
|
Chris@49
|
97 out.zeros();
|
Chris@49
|
98 return;
|
Chris@49
|
99 }
|
Chris@49
|
100
|
Chris@49
|
101 if( (N_user == 1) && (N_orig >= 1) )
|
Chris@49
|
102 {
|
Chris@49
|
103 for(uword col=0; col < n_cols; ++col) { out.at(0,col) = out_eT( P.at(0,col) ); }
|
Chris@49
|
104
|
Chris@49
|
105 return;
|
Chris@49
|
106 }
|
Chris@49
|
107
|
Chris@49
|
108 podarray<out_eT> data(N_user);
|
Chris@49
|
109
|
Chris@49
|
110 out_eT* data_mem = data.memptr();
|
Chris@49
|
111
|
Chris@49
|
112 if(N_user > N_orig) { arrayops::inplace_set( &data_mem[N_orig], out_eT(0), (N_user - N_orig) ); }
|
Chris@49
|
113
|
Chris@49
|
114 const uword N = (std::min)(N_user, N_orig);
|
Chris@49
|
115
|
Chris@49
|
116 for(uword col=0; col < n_cols; ++col)
|
Chris@49
|
117 {
|
Chris@49
|
118 for(uword i=0; i < N; ++i) { data_mem[i] = P.at(i, col); }
|
Chris@49
|
119
|
Chris@49
|
120 worker.run( out.colptr(col), data_mem );
|
Chris@49
|
121 }
|
Chris@49
|
122 }
|
Chris@49
|
123 }
|
Chris@49
|
124
|
Chris@49
|
125
|
Chris@49
|
126
|
Chris@49
|
127 //
|
Chris@49
|
128 // op_fft_cx
|
Chris@49
|
129
|
Chris@49
|
130
|
Chris@49
|
131 template<typename T1>
|
Chris@49
|
132 inline
|
Chris@49
|
133 void
|
Chris@49
|
134 op_fft_cx::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_fft_cx>& in)
|
Chris@49
|
135 {
|
Chris@49
|
136 arma_extra_debug_sigprint();
|
Chris@49
|
137
|
Chris@49
|
138 typedef typename T1::elem_type eT;
|
Chris@49
|
139
|
Chris@49
|
140 const Proxy<T1> P(in.m);
|
Chris@49
|
141
|
Chris@49
|
142 if(P.is_alias(out) == false)
|
Chris@49
|
143 {
|
Chris@49
|
144 op_fft_cx::apply_noalias<T1,false>(out, P, in.aux_uword_a, in.aux_uword_b);
|
Chris@49
|
145 }
|
Chris@49
|
146 else
|
Chris@49
|
147 {
|
Chris@49
|
148 Mat<eT> tmp;
|
Chris@49
|
149
|
Chris@49
|
150 op_fft_cx::apply_noalias<T1,false>(tmp, P, in.aux_uword_a, in.aux_uword_b);
|
Chris@49
|
151
|
Chris@49
|
152 out.steal_mem(tmp);
|
Chris@49
|
153 }
|
Chris@49
|
154 }
|
Chris@49
|
155
|
Chris@49
|
156
|
Chris@49
|
157
|
Chris@49
|
158 template<typename T1, bool inverse>
|
Chris@49
|
159 inline
|
Chris@49
|
160 void
|
Chris@49
|
161 op_fft_cx::apply_noalias(Mat<typename T1::elem_type>& out, const Proxy<T1>& P, const uword a, const uword b)
|
Chris@49
|
162 {
|
Chris@49
|
163 arma_extra_debug_sigprint();
|
Chris@49
|
164
|
Chris@49
|
165 typedef typename T1::elem_type eT;
|
Chris@49
|
166
|
Chris@49
|
167 const uword n_rows = P.get_n_rows();
|
Chris@49
|
168 const uword n_cols = P.get_n_cols();
|
Chris@49
|
169 const uword n_elem = P.get_n_elem();
|
Chris@49
|
170
|
Chris@49
|
171 const bool is_vec = ( (n_rows == 1) || (n_cols == 1) );
|
Chris@49
|
172
|
Chris@49
|
173 const uword N_orig = (is_vec) ? n_elem : n_rows;
|
Chris@49
|
174 const uword N_user = (b == 0) ? a : N_orig;
|
Chris@49
|
175
|
Chris@49
|
176 fft_engine<eT,inverse> worker(N_user);
|
Chris@49
|
177
|
Chris@49
|
178 if(is_vec)
|
Chris@49
|
179 {
|
Chris@49
|
180 (n_cols == 1) ? out.set_size(N_user, 1) : out.set_size(1, N_user);
|
Chris@49
|
181
|
Chris@49
|
182 if( (out.n_elem == 0) || (N_orig == 0) )
|
Chris@49
|
183 {
|
Chris@49
|
184 out.zeros();
|
Chris@49
|
185 return;
|
Chris@49
|
186 }
|
Chris@49
|
187
|
Chris@49
|
188 if( (N_user == 1) && (N_orig >= 1) )
|
Chris@49
|
189 {
|
Chris@49
|
190 out[0] = P[0];
|
Chris@49
|
191 return;
|
Chris@49
|
192 }
|
Chris@49
|
193
|
Chris@49
|
194 if( (N_user > N_orig) || (is_Mat<typename Proxy<T1>::stored_type>::value == false) )
|
Chris@49
|
195 {
|
Chris@49
|
196 podarray<eT> data(N_user);
|
Chris@49
|
197
|
Chris@49
|
198 eT* data_mem = data.memptr();
|
Chris@49
|
199
|
Chris@49
|
200 if(N_user > N_orig) { arrayops::inplace_set( &data_mem[N_orig], eT(0), (N_user - N_orig) ); }
|
Chris@49
|
201
|
Chris@49
|
202 op_fft_cx::copy_vec( data_mem, P, (std::min)(N_user, N_orig) );
|
Chris@49
|
203
|
Chris@49
|
204 worker.run( out.memptr(), data_mem );
|
Chris@49
|
205 }
|
Chris@49
|
206 else
|
Chris@49
|
207 {
|
Chris@49
|
208 const unwrap< typename Proxy<T1>::stored_type > tmp(P.Q);
|
Chris@49
|
209
|
Chris@49
|
210 worker.run( out.memptr(), tmp.M.memptr() );
|
Chris@49
|
211 }
|
Chris@49
|
212 }
|
Chris@49
|
213 else
|
Chris@49
|
214 {
|
Chris@49
|
215 // process each column seperately
|
Chris@49
|
216
|
Chris@49
|
217 out.set_size(N_user, n_cols);
|
Chris@49
|
218
|
Chris@49
|
219 if( (out.n_elem == 0) || (N_orig == 0) )
|
Chris@49
|
220 {
|
Chris@49
|
221 out.zeros();
|
Chris@49
|
222 return;
|
Chris@49
|
223 }
|
Chris@49
|
224
|
Chris@49
|
225 if( (N_user == 1) && (N_orig >= 1) )
|
Chris@49
|
226 {
|
Chris@49
|
227 for(uword col=0; col < n_cols; ++col) { out.at(0,col) = P.at(0,col); }
|
Chris@49
|
228
|
Chris@49
|
229 return;
|
Chris@49
|
230 }
|
Chris@49
|
231
|
Chris@49
|
232 if( (N_user > N_orig) || (is_Mat<typename Proxy<T1>::stored_type>::value == false) )
|
Chris@49
|
233 {
|
Chris@49
|
234 podarray<eT> data(N_user);
|
Chris@49
|
235
|
Chris@49
|
236 eT* data_mem = data.memptr();
|
Chris@49
|
237
|
Chris@49
|
238 if(N_user > N_orig) { arrayops::inplace_set( &data_mem[N_orig], eT(0), (N_user - N_orig) ); }
|
Chris@49
|
239
|
Chris@49
|
240 const uword N = (std::min)(N_user, N_orig);
|
Chris@49
|
241
|
Chris@49
|
242 for(uword col=0; col < n_cols; ++col)
|
Chris@49
|
243 {
|
Chris@49
|
244 for(uword i=0; i < N; ++i) { data_mem[i] = P.at(i, col); }
|
Chris@49
|
245
|
Chris@49
|
246 worker.run( out.colptr(col), data_mem );
|
Chris@49
|
247 }
|
Chris@49
|
248 }
|
Chris@49
|
249 else
|
Chris@49
|
250 {
|
Chris@49
|
251 const unwrap< typename Proxy<T1>::stored_type > tmp(P.Q);
|
Chris@49
|
252
|
Chris@49
|
253 for(uword col=0; col < n_cols; ++col)
|
Chris@49
|
254 {
|
Chris@49
|
255 worker.run( out.colptr(col), tmp.M.colptr(col) );
|
Chris@49
|
256 }
|
Chris@49
|
257 }
|
Chris@49
|
258 }
|
Chris@49
|
259
|
Chris@49
|
260
|
Chris@49
|
261 // correct the scaling for the inverse transform
|
Chris@49
|
262 if(inverse == true)
|
Chris@49
|
263 {
|
Chris@49
|
264 typedef typename get_pod_type<eT>::result T;
|
Chris@49
|
265
|
Chris@49
|
266 const T k = T(1) / T(N_user);
|
Chris@49
|
267
|
Chris@49
|
268 eT* out_mem = out.memptr();
|
Chris@49
|
269
|
Chris@49
|
270 const uword out_n_elem = out.n_elem;
|
Chris@49
|
271
|
Chris@49
|
272 for(uword i=0; i < out_n_elem; ++i) { out_mem[i] *= k; }
|
Chris@49
|
273 }
|
Chris@49
|
274 }
|
Chris@49
|
275
|
Chris@49
|
276
|
Chris@49
|
277
|
Chris@49
|
278 template<typename T1>
|
Chris@49
|
279 arma_hot
|
Chris@49
|
280 inline
|
Chris@49
|
281 void
|
Chris@49
|
282 op_fft_cx::copy_vec(typename Proxy<T1>::elem_type* dest, const Proxy<T1>& P, const uword N)
|
Chris@49
|
283 {
|
Chris@49
|
284 arma_extra_debug_sigprint();
|
Chris@49
|
285
|
Chris@49
|
286 if(is_Mat< typename Proxy<T1>::stored_type >::value == true)
|
Chris@49
|
287 {
|
Chris@49
|
288 op_fft_cx::copy_vec_unwrap(dest, P, N);
|
Chris@49
|
289 }
|
Chris@49
|
290 else
|
Chris@49
|
291 {
|
Chris@49
|
292 op_fft_cx::copy_vec_proxy(dest, P, N);
|
Chris@49
|
293 }
|
Chris@49
|
294 }
|
Chris@49
|
295
|
Chris@49
|
296
|
Chris@49
|
297
|
Chris@49
|
298 template<typename T1>
|
Chris@49
|
299 arma_hot
|
Chris@49
|
300 inline
|
Chris@49
|
301 void
|
Chris@49
|
302 op_fft_cx::copy_vec_unwrap(typename Proxy<T1>::elem_type* dest, const Proxy<T1>& P, const uword N)
|
Chris@49
|
303 {
|
Chris@49
|
304 arma_extra_debug_sigprint();
|
Chris@49
|
305
|
Chris@49
|
306 const unwrap< typename Proxy<T1>::stored_type > tmp(P.Q);
|
Chris@49
|
307
|
Chris@49
|
308 arrayops::copy(dest, tmp.M.memptr(), N);
|
Chris@49
|
309 }
|
Chris@49
|
310
|
Chris@49
|
311
|
Chris@49
|
312
|
Chris@49
|
313 template<typename T1>
|
Chris@49
|
314 arma_hot
|
Chris@49
|
315 inline
|
Chris@49
|
316 void
|
Chris@49
|
317 op_fft_cx::copy_vec_proxy(typename Proxy<T1>::elem_type* dest, const Proxy<T1>& P, const uword N)
|
Chris@49
|
318 {
|
Chris@49
|
319 arma_extra_debug_sigprint();
|
Chris@49
|
320
|
Chris@49
|
321 if(Proxy<T1>::prefer_at_accessor == false)
|
Chris@49
|
322 {
|
Chris@49
|
323 typename Proxy<T1>::ea_type X = P.get_ea();
|
Chris@49
|
324
|
Chris@49
|
325 for(uword i=0; i < N; ++i) { dest[i] = X[i]; }
|
Chris@49
|
326 }
|
Chris@49
|
327 else
|
Chris@49
|
328 {
|
Chris@49
|
329 if(P.get_n_cols() == 1)
|
Chris@49
|
330 {
|
Chris@49
|
331 for(uword i=0; i < N; ++i) { dest[i] = P.at(i,0); }
|
Chris@49
|
332 }
|
Chris@49
|
333 else
|
Chris@49
|
334 {
|
Chris@49
|
335 for(uword i=0; i < N; ++i) { dest[i] = P.at(0,i); }
|
Chris@49
|
336 }
|
Chris@49
|
337 }
|
Chris@49
|
338 }
|
Chris@49
|
339
|
Chris@49
|
340
|
Chris@49
|
341
|
Chris@49
|
342 //
|
Chris@49
|
343 // op_ifft_cx
|
Chris@49
|
344
|
Chris@49
|
345
|
Chris@49
|
346 template<typename T1>
|
Chris@49
|
347 inline
|
Chris@49
|
348 void
|
Chris@49
|
349 op_ifft_cx::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_ifft_cx>& in)
|
Chris@49
|
350 {
|
Chris@49
|
351 arma_extra_debug_sigprint();
|
Chris@49
|
352
|
Chris@49
|
353 typedef typename T1::elem_type eT;
|
Chris@49
|
354
|
Chris@49
|
355 const Proxy<T1> P(in.m);
|
Chris@49
|
356
|
Chris@49
|
357 if(P.is_alias(out) == false)
|
Chris@49
|
358 {
|
Chris@49
|
359 op_fft_cx::apply_noalias<T1,true>(out, P, in.aux_uword_a, in.aux_uword_b);
|
Chris@49
|
360 }
|
Chris@49
|
361 else
|
Chris@49
|
362 {
|
Chris@49
|
363 Mat<eT> tmp;
|
Chris@49
|
364
|
Chris@49
|
365 op_fft_cx::apply_noalias<T1,true>(tmp, P, in.aux_uword_a, in.aux_uword_b);
|
Chris@49
|
366
|
Chris@49
|
367 out.steal_mem(tmp);
|
Chris@49
|
368 }
|
Chris@49
|
369 }
|
Chris@49
|
370
|
Chris@49
|
371
|
Chris@49
|
372
|
Chris@49
|
373 //! @}
|