1 /* ************************************************************************
2  * Copyright 2013 Advanced Micro Devices, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  * ************************************************************************/
16 
17 
18 #include <gtest/gtest.h>
19 #include<math.h>
20 
21 #include "test_constants.h"
22 #include "fftw_transform.h"
23 #include "cl_transform.h"
24 #include "buffer.h"
25 #include "typedefs.h"
26 #include <stdexcept>
27 #include <vector>
28 
29 namespace placeness
30 {
31 	enum placeness_t { in_place = CLFFT_INPLACE, out_of_place = CLFFT_OUTOFPLACE };
32 }
33 
34 enum data_pattern { impulse, sawtooth, value, erratic };
35 
36 namespace direction
37 {
38 	enum direction_t { forward, backward };
39 }
40 
41 clfftResultLocation cl_placeness( placeness::placeness_t placeness );
42 clfftLayout cl_layout( layout::buffer_layout_t layout_in );
43 
44 
45 /*****************************************************/
46 /*****************************************************/
47 // dimension is inferred from lengths.size()
48 // tightly packed is inferred from strides.empty()
49 template< class T, class cl_T, class fftw_T >
50 void complex_to_complex( data_pattern pattern, direction::direction_t direction,
51 	std::vector<size_t> lengths, size_t batch,
52 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
53 	size_t input_distance, size_t output_distance,
54 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
55 	placeness::placeness_t placeness,
56 	T scale = 1.0f )
57 {
58 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
59 		input_strides.empty() ? NULL : &input_strides[0],
60 		output_strides.empty() ? NULL : &output_strides[0],
61 		batch, input_distance, output_distance,
62 		cl_layout(in_layout), cl_layout(out_layout),
63 		cl_placeness(placeness) );
64 
65 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
66 
67 	if( pattern == sawtooth )
68 	{
69 		test_fft.set_input_to_sawtooth( 1.0f );
70 		reference.set_data_to_sawtooth( 1.0f );
71 	}
72 	else if( pattern == value )
73 	{
74 		test_fft.set_input_to_value( 2.0f, 2.5f );
75 		reference.set_all_data_to_value( 2.0f, 2.5f );
76 	}
77 	else if( pattern == impulse )
78 	{
79 		test_fft.set_input_to_impulse();
80 		reference.set_data_to_impulse();
81 	}
82 	else if( pattern == erratic )
83 	{
84 		test_fft.set_input_to_random();
85 		reference.set_data_to_random();
86 	}
87 	else
88 	{
89 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
90 	}
91 
92 	// if we're starting with unequal data, we're destined for failure
93 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
94 
95 	if( direction == direction::forward )
96 	{
97 		test_fft.set_forward_transform();
98 		test_fft.forward_scale( scale );
99 
100 		reference.set_forward_transform();
101 		reference.forward_scale( scale );
102 	}
103 	else if( direction == direction::backward )
104 	{
105 		test_fft.set_backward_transform();
106 		test_fft.backward_scale( scale );
107 
108 		reference.set_backward_transform();
109 		reference.backward_scale( scale );
110 	}
111 	else
112 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
113 	reference.transform();
114 	test_fft.transform();
115 
116 	EXPECT_EQ( true, test_fft.result() == reference.result() );
117 }
118 
119 /*****************************************************/
120 /*****************************************************/
121 // complex to complex transform with precallback
122 // dimension is inferred from lengths.size()
123 // tightly packed is inferred from strides.empty()
124 template< class T, class cl_T, class fftw_T >
125 void precallback_complex_to_complex( data_pattern pattern, direction::direction_t direction,
126 	std::vector<size_t> lengths, size_t batch,
127 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
128 	size_t input_distance, size_t output_distance,
129 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
130 	placeness::placeness_t placeness, T scale = 1.0f, bool hasUserDatatype = false )
131 {
132 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
133 		input_strides.empty() ? NULL : &input_strides[0],
134 		output_strides.empty() ? NULL : &output_strides[0],
135 		batch, input_distance, output_distance,
136 		cl_layout(in_layout), cl_layout(out_layout),
137 		cl_placeness(placeness) );
138 
139 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
140 
141 	//initialize input
142 	if( pattern == sawtooth )
143 	{
144 		test_fft.set_input_to_sawtooth( 1.0f );
145 		reference.set_data_to_sawtooth( 1.0f );
146 	}
147 	else if( pattern == value )
148 	{
149 		test_fft.set_input_to_value( 2.0f, 2.5f );
150 		reference.set_all_data_to_value( 2.0f, 2.5f );
151 	}
152 	else if( pattern == impulse )
153 	{
154 		test_fft.set_input_to_impulse();
155 		reference.set_data_to_impulse();
156 	}
157 	else if( pattern == erratic )
158 	{
159 		test_fft.set_input_to_random();
160 		reference.set_data_to_random();
161 	}
162 	else
163 	{
164 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
165 	}
166 
167 	// if we're starting with unequal data, we're destined for failure
168 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
169 
170 	//set precallback values
171 	if (hasUserDatatype)
172 	{
173 		test_fft.set_input_precallback_userdatatype();
174 	}
175 	else
176 	{
177 		test_fft.set_input_precallback();
178 	}
179 	reference.set_input_precallback();
180 
181 	if( direction == direction::forward )
182 	{
183 		test_fft.set_forward_transform();
184 		test_fft.forward_scale( scale );
185 
186 		reference.set_forward_transform();
187 		reference.forward_scale( scale );
188 	}
189 	else if( direction == direction::backward )
190 	{
191 		test_fft.set_backward_transform();
192 		test_fft.backward_scale( scale );
193 
194 		reference.set_backward_transform();
195 		reference.backward_scale( scale );
196 	}
197 	else
198 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
199 
200 	reference.transform();
201 	test_fft.transform();
202 
203 	EXPECT_EQ( true, test_fft.result() == reference.result() );
204 }
205 
206 /*****************************************************/
207 /*****************************************************/
208 // complex to complex transform with postcallback
209 // dimension is inferred from lengths.size()
210 // tightly packed is inferred from strides.empty()
211 template< class T, class cl_T, class fftw_T >
212 void postcallback_complex_to_complex( data_pattern pattern, direction::direction_t direction,
213 	std::vector<size_t> lengths, size_t batch,
214 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
215 	size_t input_distance, size_t output_distance,
216 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
217 	placeness::placeness_t placeness, T scale = 1.0f, bool hasUserDatatype = false )
218 {
219 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
220 		input_strides.empty() ? NULL : &input_strides[0],
221 		output_strides.empty() ? NULL : &output_strides[0],
222 		batch, input_distance, output_distance,
223 		cl_layout(in_layout), cl_layout(out_layout),
224 		cl_placeness(placeness) );
225 
226 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
227 
228 	//initialize input
229 	if( pattern == sawtooth )
230 	{
231 		test_fft.set_input_to_sawtooth( 1.0f );
232 		reference.set_data_to_sawtooth( 1.0f );
233 	}
234 	else if( pattern == value )
235 	{
236 		test_fft.set_input_to_value( 2.0f, 2.5f );
237 		reference.set_all_data_to_value( 2.0f, 2.5f );
238 	}
239 	else if( pattern == impulse )
240 	{
241 		test_fft.set_input_to_impulse();
242 		reference.set_data_to_impulse();
243 	}
244 	else if( pattern == erratic )
245 	{
246 		test_fft.set_input_to_random();
247 		reference.set_data_to_random();
248 	}
249 	else
250 	{
251 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
252 	}
253 
254 	// if we're starting with unequal data, we're destined for failure
255 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
256 
257 	//set postcallback values
258 	if (hasUserDatatype)
259 	{
260 		//test_fft.set_input_precallback_userdatatype();
261 	}
262 	else
263 	{
264 		test_fft.set_output_postcallback();
265 	}
266 
267 	if( direction == direction::forward )
268 	{
269 		test_fft.set_forward_transform();
270 		test_fft.forward_scale( scale );
271 
272 		reference.set_forward_transform();
273 		reference.forward_scale( scale );
274 	}
275 	else if( direction == direction::backward )
276 	{
277 		test_fft.set_backward_transform();
278 		test_fft.backward_scale( scale );
279 
280 		reference.set_backward_transform();
281 		reference.backward_scale( scale );
282 	}
283 	else
284 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
285 
286 	reference.transform();
287 	test_fft.transform();
288 
289 	reference.set_output_postcallback();
290 
291 	EXPECT_EQ( true, test_fft.result() == reference.result() );
292 }
293 
294 /*****************************************************/
295 /*****************************************************/
296 // complex to complex transform with pre and post callback
297 // dimension is inferred from lengths.size()
298 // tightly packed is inferred from strides.empty()
299 template< class T, class cl_T, class fftw_T >
300 void pre_and_post_callback_complex_to_complex( data_pattern pattern, direction::direction_t direction,
301 	std::vector<size_t> lengths, size_t batch,
302 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
303 	size_t input_distance, size_t output_distance,
304 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
305 	placeness::placeness_t placeness, T scale = 1.0f, bool withLDS = false)
306 {
307 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
308 		input_strides.empty() ? NULL : &input_strides[0],
309 		output_strides.empty() ? NULL : &output_strides[0],
310 		batch, input_distance, output_distance,
311 		cl_layout(in_layout), cl_layout(out_layout),
312 		cl_placeness(placeness) );
313 
314 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
315 
316 	//initialize input
317 	if( pattern == sawtooth )
318 	{
319 		test_fft.set_input_to_sawtooth( 1.0f );
320 		reference.set_data_to_sawtooth( 1.0f );
321 	}
322 	else if( pattern == value )
323 	{
324 		test_fft.set_input_to_value( 2.0f, 2.5f );
325 		reference.set_all_data_to_value( 2.0f, 2.5f );
326 	}
327 	else if( pattern == impulse )
328 	{
329 		test_fft.set_input_to_impulse();
330 		reference.set_data_to_impulse();
331 	}
332 	else if( pattern == erratic )
333 	{
334 		test_fft.set_input_to_random();
335 		reference.set_data_to_random();
336 	}
337 	else
338 	{
339 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
340 	}
341 
342 	// if we're starting with unequal data, we're destined for failure
343 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
344 
345 	//set callback values
346 	if (withLDS)
347 	{
348 		unsigned int localMemSize = 64 * sizeof(T);
349 		test_fft.set_input_precallback(localMemSize);
350 		reference.set_input_precallback_special();
351 
352 		test_fft.set_output_postcallback(localMemSize);
353 	}
354 	else
355 	{
356 		test_fft.set_input_precallback();
357 		reference.set_input_precallback();
358 
359 		//set postcallback values
360 		test_fft.set_output_postcallback();
361 	}
362 
363 	if( direction == direction::forward )
364 	{
365 		test_fft.set_forward_transform();
366 		test_fft.forward_scale( scale );
367 
368 		reference.set_forward_transform();
369 		reference.forward_scale( scale );
370 	}
371 	else if( direction == direction::backward )
372 	{
373 		test_fft.set_backward_transform();
374 		test_fft.backward_scale( scale );
375 
376 		reference.set_backward_transform();
377 		reference.backward_scale( scale );
378 	}
379 	else
380 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
381 
382 	reference.transform();
383 	test_fft.transform();
384 
385 	//update reference for postcallback
386 	if (withLDS)
387 	{
388 		reference.set_output_postcallback_special();
389 	}
390 	else
391 	{
392 		reference.set_output_postcallback();
393 	}
394 
395 	EXPECT_EQ( true, test_fft.result() == reference.result() );
396 }
397 
398 /*****************************************************/
399 /*****************************************************/
400 // complex to complex transform with precallback function that uses LDS
401 template< class T, class cl_T, class fftw_T >
402 void precallback_complex_to_complex_lds( data_pattern pattern, direction::direction_t direction,
403 	std::vector<size_t> lengths, size_t batch,
404 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
405 	size_t input_distance, size_t output_distance,
406 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
407 	placeness::placeness_t placeness,
408 	T scale = 1.0f )
409 {
410 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
411 		input_strides.empty() ? NULL : &input_strides[0],
412 		output_strides.empty() ? NULL : &output_strides[0],
413 		batch, input_distance, output_distance,
414 		cl_layout(in_layout), cl_layout(out_layout),
415 		cl_placeness(placeness) );
416 
417 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
418 
419 	//initialize input
420 	if( pattern == sawtooth )
421 	{
422 		test_fft.set_input_to_sawtooth( 1.0f );
423 		reference.set_data_to_sawtooth( 1.0f );
424 	}
425 	else if( pattern == value )
426 	{
427 		test_fft.set_input_to_value( 2.0f, 2.5f );
428 		reference.set_all_data_to_value( 2.0f, 2.5f );
429 	}
430 	else if( pattern == impulse )
431 	{
432 		test_fft.set_input_to_impulse();
433 		reference.set_data_to_impulse();
434 	}
435 	else if( pattern == erratic )
436 	{
437 		test_fft.set_input_to_random();
438 		reference.set_data_to_random();
439 	}
440 	else
441 	{
442 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
443 	}
444 
445 	// if we're starting with unequal data, we're destined for failure
446 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
447 
448 	//set precallback values
449 	//Test assumes 64 length data
450 	unsigned int localMemSize = 64 * sizeof(T);
451 	test_fft.set_input_precallback(localMemSize);
452 	reference.set_input_precallback_special();
453 
454 	if( direction == direction::forward )
455 	{
456 		test_fft.set_forward_transform();
457 		test_fft.forward_scale( scale );
458 
459 		reference.set_forward_transform();
460 		reference.forward_scale( scale );
461 	}
462 	else if( direction == direction::backward )
463 	{
464 		test_fft.set_backward_transform();
465 		test_fft.backward_scale( scale );
466 
467 		reference.set_backward_transform();
468 		reference.backward_scale( scale );
469 	}
470 	else
471 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
472 
473 	reference.transform();
474 	test_fft.transform();
475 
476 	EXPECT_EQ( true, test_fft.result() == reference.result() );
477 }
478 
479 /*****************************************************/
480 /*****************************************************/
481 // complex to complex transform with postcallback function that uses LDS
482 template< class T, class cl_T, class fftw_T >
483 void postcallback_complex_to_complex_lds( data_pattern pattern, direction::direction_t direction,
484 	std::vector<size_t> lengths, size_t batch,
485 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
486 	size_t input_distance, size_t output_distance,
487 	layout::buffer_layout_t in_layout, layout::buffer_layout_t out_layout,
488 	placeness::placeness_t placeness, T scale = 1.0f )
489 {
490 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
491 		input_strides.empty() ? NULL : &input_strides[0],
492 		output_strides.empty() ? NULL : &output_strides[0],
493 		batch, input_distance, output_distance,
494 		cl_layout(in_layout), cl_layout(out_layout),
495 		cl_placeness(placeness) );
496 
497 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2c );
498 
499 	//initialize input
500 	if( pattern == sawtooth )
501 	{
502 		test_fft.set_input_to_sawtooth( 1.0f );
503 		reference.set_data_to_sawtooth( 1.0f );
504 	}
505 	else if( pattern == value )
506 	{
507 		test_fft.set_input_to_value( 2.0f, 2.5f );
508 		reference.set_all_data_to_value( 2.0f, 2.5f );
509 	}
510 	else if( pattern == impulse )
511 	{
512 		test_fft.set_input_to_impulse();
513 		reference.set_data_to_impulse();
514 	}
515 	else if( pattern == erratic )
516 	{
517 		test_fft.set_input_to_random();
518 		reference.set_data_to_random();
519 	}
520 	else
521 	{
522 		throw std::runtime_error( "invalid pattern type in complex_to_complex()" );
523 	}
524 
525 	// if we're starting with unequal data, we're destined for failure
526 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
527 
528 	//set postcallback values
529 	//Test assumes 64 length data
530 	unsigned int localMemSize = 64 * sizeof(T);
531 	test_fft.set_output_postcallback(localMemSize);
532 
533 	if( direction == direction::forward )
534 	{
535 		test_fft.set_forward_transform();
536 		test_fft.forward_scale( scale );
537 
538 		reference.set_forward_transform();
539 		reference.forward_scale( scale );
540 	}
541 	else if( direction == direction::backward )
542 	{
543 		test_fft.set_backward_transform();
544 		test_fft.backward_scale( scale );
545 
546 		reference.set_backward_transform();
547 		reference.backward_scale( scale );
548 	}
549 	else
550 		throw std::runtime_error( "invalid direction in complex_to_complex()" );
551 
552 	reference.transform();
553 	test_fft.transform();
554 
555 	reference.set_output_postcallback_special();
556 
557 	EXPECT_EQ( true, test_fft.result() == reference.result() );
558 }
559 
560 /*****************************************************/
561 /*****************************************************/
562 // dimension is inferred from lengths.size()
563 // tightly packed is inferred from strides.empty()
564 // input layout is always real
565 template< class T, class cl_T, class fftw_T >
566 void real_to_complex( data_pattern pattern,
567 	std::vector<size_t> lengths, size_t batch,
568 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
569 	size_t input_distance, size_t output_distance,
570 	layout::buffer_layout_t out_layout,
571 	placeness::placeness_t placeness,
572 	T scale = 1.0f )
573 {
574 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
575 		input_strides.empty() ? NULL : &input_strides[0],
576 		output_strides.empty() ? NULL : &output_strides[0],
577 		batch, input_distance, output_distance,
578 		cl_layout(layout::real), cl_layout(out_layout),
579 		cl_placeness(placeness) );
580 
581 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, r2c );
582 
583 	if( pattern == sawtooth )
584 	{
585 		test_fft.set_input_to_sawtooth( 1.0f );
586 		reference.set_data_to_sawtooth( 1.0f );
587 	}
588 	else if( pattern == value )
589 	{
590 		test_fft.set_input_to_value( 2.0f );
591 		reference.set_all_data_to_value( 2.0f );
592 	}
593 	else if( pattern == impulse )
594 	{
595 		test_fft.set_input_to_impulse();
596 		reference.set_data_to_impulse();
597 	}
598 	else if( pattern == erratic )
599 	{
600 		test_fft.set_input_to_random();
601 		reference.set_data_to_random();
602 	}
603 	else
604 	{
605 		throw std::runtime_error( "invalid pattern type in real_to_complex()" );
606 	}
607 
608 	// if we're starting with unequal data, we're destined for failure
609 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
610 
611 	test_fft.forward_scale( scale );
612 	reference.forward_scale( scale );
613 
614 	test_fft.transform();
615 	reference.transform();
616 
617 	EXPECT_EQ( true, test_fft.result() == reference.result() );
618 }
619 
620 /*****************************************************/
621 /*****************************************************/
622 // dimension is inferred from lengths.size()
623 // tightly packed is inferred from strides.empty()
624 // input layout is always real
625 template< class T, class cl_T, class fftw_T >
626 void precallback_real_to_complex( data_pattern pattern,
627 	std::vector<size_t> lengths, size_t batch,
628 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
629 	size_t input_distance, size_t output_distance,
630 	layout::buffer_layout_t out_layout,
631 	placeness::placeness_t placeness,
632 	T scale = 1.0f )
633 {
634 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
635 		input_strides.empty() ? NULL : &input_strides[0],
636 		output_strides.empty() ? NULL : &output_strides[0],
637 		batch, input_distance, output_distance,
638 		cl_layout(layout::real), cl_layout(out_layout),
639 		cl_placeness(placeness) );
640 
641 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, r2c );
642 
643 	if( pattern == sawtooth )
644 	{
645 		test_fft.set_input_to_sawtooth( 1.0f );
646 		reference.set_data_to_sawtooth( 1.0f );
647 	}
648 	else if( pattern == value )
649 	{
650 		test_fft.set_input_to_value( 2.0f );
651 		reference.set_all_data_to_value( 2.0f );
652 	}
653 	else if( pattern == impulse )
654 	{
655 		test_fft.set_input_to_impulse();
656 		reference.set_data_to_impulse();
657 	}
658 	else if( pattern == erratic )
659 	{
660 		test_fft.set_input_to_random();
661 		reference.set_data_to_random();
662 	}
663 	else
664 	{
665 		throw std::runtime_error( "invalid pattern type in real_to_complex()" );
666 	}
667 
668 	// if we're starting with unequal data, we're destined for failure
669 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
670 
671 	test_fft.set_input_precallback();
672 	reference.set_input_precallback();
673 
674 	test_fft.forward_scale( scale );
675 	reference.forward_scale( scale );
676 
677 	test_fft.transform();
678 	reference.transform();
679 
680 	EXPECT_EQ( true, test_fft.result() == reference.result() );
681 }
682 
683 /*****************************************************/
684 /*****************************************************/
685 // dimension is inferred from lengths.size()
686 // tightly packed is inferred from strides.empty()
687 // input layout is always real
688 template< class T, class cl_T, class fftw_T >
689 void postcallback_real_to_complex( data_pattern pattern,
690 	std::vector<size_t> lengths, size_t batch,
691 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
692 	size_t input_distance, size_t output_distance,
693 	layout::buffer_layout_t out_layout,
694 	placeness::placeness_t placeness,
695 	T scale = 1.0f )
696 {
697 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
698 		input_strides.empty() ? NULL : &input_strides[0],
699 		output_strides.empty() ? NULL : &output_strides[0],
700 		batch, input_distance, output_distance,
701 		cl_layout(layout::real), cl_layout(out_layout),
702 		cl_placeness(placeness) );
703 
704 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, r2c );
705 
706 	if( pattern == sawtooth )
707 	{
708 		test_fft.set_input_to_sawtooth( 1.0f );
709 		reference.set_data_to_sawtooth( 1.0f );
710 	}
711 	else if( pattern == value )
712 	{
713 		test_fft.set_input_to_value( 2.0f );
714 		reference.set_all_data_to_value( 2.0f );
715 	}
716 	else if( pattern == impulse )
717 	{
718 		test_fft.set_input_to_impulse();
719 		reference.set_data_to_impulse();
720 	}
721 	else if( pattern == erratic )
722 	{
723 		test_fft.set_input_to_random();
724 		reference.set_data_to_random();
725 	}
726 	else
727 	{
728 		throw std::runtime_error( "invalid pattern type in real_to_complex()" );
729 	}
730 
731 	// if we're starting with unequal data, we're destined for failure
732 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
733 
734 	test_fft.forward_scale( scale );
735 	reference.forward_scale( scale );
736 
737 	//set postcallback values
738 	test_fft.set_output_postcallback();
739 
740 	test_fft.transform();
741 	reference.transform();
742 
743 	reference.set_output_postcallback();
744 
745 	EXPECT_EQ( true, test_fft.result() == reference.result() );
746 }
747 
748 /*****************************************************/
749 /*****************************************************/
750 // dimension is inferred from lengths.size()
751 // tightly packed is inferred from strides.empty()
752 // output layout is always real
753 template< class T, class cl_T, class fftw_T >
754 void complex_to_real( data_pattern pattern,
755 	std::vector<size_t> lengths, size_t batch,
756 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
757 	size_t input_distance, size_t output_distance,
758 	layout::buffer_layout_t in_layout,
759 	placeness::placeness_t placeness,
760 	T scale = 1.0f )
761 {
762 	fftw<T, fftw_T> data_maker( lengths.size(), &lengths[0], batch, r2c );
763 
764 	if( pattern == sawtooth )
765 	{
766 		data_maker.set_data_to_sawtooth(1.0f);
767 	}
768 	else if( pattern == value )
769 	{
770 		data_maker.set_all_data_to_value(2.0f);
771 	}
772 	else if( pattern == impulse )
773 	{
774 		data_maker.set_data_to_impulse();
775 	}
776 	else if( pattern == erratic )
777 	{
778 		data_maker.set_data_to_random();
779 	}
780 	else
781 	{
782 		throw std::runtime_error( "invalid pattern type in complex_to_real()" );
783 	}
784 
785 	data_maker.transform();
786 
787 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
788 		input_strides.empty() ? NULL : &input_strides[0],
789 		output_strides.empty() ? NULL : &output_strides[0],
790 		batch, input_distance, output_distance,
791 		cl_layout(in_layout), cl_layout(layout::real),
792 		cl_placeness(placeness) );
793 	test_fft.set_input_to_buffer( data_maker.result() );
794 
795 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2r );
796 	reference.set_input_to_buffer(data_maker.result());
797 
798 	// if we're starting with unequal data, we're destined for failure
799 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
800 
801 	test_fft.backward_scale( scale );
802 	reference.backward_scale( scale );
803 
804 	test_fft.transform();
805 	reference.transform();
806 
807 	EXPECT_EQ( true, test_fft.result() == reference.result() );
808 }
809 
810 /*****************************************************/
811 /*****************************************************/
812 // dimension is inferred from lengths.size()
813 // tightly packed is inferred from strides.empty()
814 // output layout is always real
815 template< class T, class cl_T, class fftw_T >
816 void precallback_complex_to_real( data_pattern pattern,
817 	std::vector<size_t> lengths, size_t batch,
818 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
819 	size_t input_distance, size_t output_distance,
820 	layout::buffer_layout_t in_layout,
821 	placeness::placeness_t placeness,
822 	T scale = 1.0f )
823 {
824 	fftw<T, fftw_T> data_maker( lengths.size(), &lengths[0], batch, r2c );
825 
826 	if( pattern == sawtooth )
827 	{
828 		data_maker.set_data_to_sawtooth(1.0f);
829 	}
830 	else if( pattern == value )
831 	{
832 		data_maker.set_all_data_to_value(2.0f);
833 	}
834 	else if( pattern == impulse )
835 	{
836 		data_maker.set_data_to_impulse();
837 	}
838 	else if( pattern == erratic )
839 	{
840 		data_maker.set_data_to_random();
841 	}
842 	else
843 	{
844 		throw std::runtime_error( "invalid pattern type in complex_to_real()" );
845 	}
846 
847 	data_maker.transform();
848 
849 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
850 		input_strides.empty() ? NULL : &input_strides[0],
851 		output_strides.empty() ? NULL : &output_strides[0],
852 		batch, input_distance, output_distance,
853 		cl_layout(in_layout), cl_layout(layout::real),
854 		cl_placeness(placeness) );
855 	test_fft.set_input_to_buffer( data_maker.result() );
856 
857 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2r );
858 	reference.set_input_to_buffer(data_maker.result());
859 
860 	// if we're starting with unequal data, we're destined for failure
861 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
862 
863 	test_fft.set_input_precallback();
864 	reference.set_input_precallback();
865 
866 	test_fft.backward_scale( scale );
867 	reference.backward_scale( scale );
868 
869 	test_fft.transform();
870 	reference.transform();
871 
872 	EXPECT_EQ( true, test_fft.result() == reference.result() );
873 }
874 
875 template< class T, class cl_T, class fftw_T >
876 void postcallback_complex_to_real( data_pattern pattern,
877 	std::vector<size_t> lengths, size_t batch,
878 	std::vector<size_t> input_strides, std::vector<size_t> output_strides,
879 	size_t input_distance, size_t output_distance,
880 	layout::buffer_layout_t in_layout,
881 	placeness::placeness_t placeness,
882 	T scale = 1.0f )
883 {
884 	fftw<T, fftw_T> data_maker( lengths.size(), &lengths[0], batch, r2c );
885 
886 	if( pattern == sawtooth )
887 	{
888 		data_maker.set_data_to_sawtooth(1.0f);
889 	}
890 	else if( pattern == value )
891 	{
892 		data_maker.set_all_data_to_value(2.0f);
893 	}
894 	else if( pattern == impulse )
895 	{
896 		data_maker.set_data_to_impulse();
897 	}
898 	else if( pattern == erratic )
899 	{
900 		data_maker.set_data_to_random();
901 	}
902 	else
903 	{
904 		throw std::runtime_error( "invalid pattern type in complex_to_real()" );
905 	}
906 
907 	data_maker.transform();
908 
909 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
910 		input_strides.empty() ? NULL : &input_strides[0],
911 		output_strides.empty() ? NULL : &output_strides[0],
912 		batch, input_distance, output_distance,
913 		cl_layout(in_layout), cl_layout(layout::real),
914 		cl_placeness(placeness) );
915 	test_fft.set_input_to_buffer( data_maker.result() );
916 
917 	fftw<T, fftw_T> reference( lengths.size(), &lengths[0], batch, c2r );
918 	reference.set_input_to_buffer(data_maker.result());
919 
920 	// if we're starting with unequal data, we're destined for failure
921 	EXPECT_EQ( true, test_fft.input_buffer() == reference.input_buffer() );
922 
923 	test_fft.backward_scale( scale );
924 	reference.backward_scale( scale );
925 
926 	//set postcallback values
927 	test_fft.set_output_postcallback();
928 
929 	test_fft.transform();
930 	reference.transform();
931 
932 	reference.set_output_postcallback();
933 
934 	EXPECT_EQ( true, test_fft.result() == reference.result() );
935 }
936 
937 /*****************************************************/
938 /*****************************************************/
939 // dimension is inferred from lengths.size()
940 // tightly packed is inferred from strides.empty()
941 
942 // no need to support non-unit strides and distances here
943 // they are covered in plenty of other places
944 // and just needlessly complicate things in this case
945 template< class T, class cl_T, class fftw_T >
complex_to_complex_round_trip(data_pattern pattern,std::vector<size_t> lengths,size_t batch,layout::buffer_layout_t layout)946 void complex_to_complex_round_trip( data_pattern pattern,
947 									std::vector<size_t> lengths, size_t batch,
948 									layout::buffer_layout_t layout )
949 {
950 	placeness::placeness_t placeness = placeness::in_place;
951 
952 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
953 		NULL, NULL,	batch, 0, 0,
954 		cl_layout(layout), cl_layout(layout),
955 		cl_placeness( placeness ) );
956 
957 	buffer<T> expected( lengths.size(), &lengths[0], NULL, batch, 0, layout, CLFFT_OUTOFPLACE );
958 
959 	if( pattern == sawtooth )
960 	{
961 		test_fft.set_input_to_sawtooth( 1.0f );
962 		expected.set_all_to_sawtooth( 1.0f );
963 	}
964 	else if( pattern == value )
965 	{
966 		test_fft.set_input_to_value( 2.0f, 2.5f );
967 		expected.set_all_to_value( 2.0f, 2.5f );
968 	}
969 	else if( pattern == impulse )
970 	{
971 		test_fft.set_input_to_impulse();
972 		expected.set_all_to_impulse();
973 	}
974 	else if( pattern == erratic )
975 	{
976 		test_fft.set_input_to_random();
977 		expected.set_all_to_random_data( 10, super_duper_global_seed );
978 	}
979 	else
980 	{
981 		throw std::runtime_error( "invalid pattern type in complex_to_complex_round_trip()" );
982 	}
983 
984 	// if we're starting with unequal data, we're destined for failure
985 	EXPECT_EQ( true, test_fft.input_buffer() == expected );
986 
987 	test_fft.set_forward_transform();
988 	test_fft.transform();
989 
990 	// confirm that we actually did something
991 	bool stash_suppress_output = suppress_output;
992 	suppress_output = true;
993 	EXPECT_EQ( false, test_fft.result() == expected );
994 	suppress_output = stash_suppress_output;
995 
996 	test_fft.set_backward_transform();
997 	test_fft.transform();
998 
999 	EXPECT_EQ( true, test_fft.result() == expected );
1000 }
1001 
1002 /*****************************************************/
1003 /*****************************************************/
1004 // dimension is inferred from lengths.size()
1005 // tightly packed is inferred from strides.empty()
1006 // no need to support non-unit strides and distances here
1007 // they are covered in plenty of other places
1008 // and just needlessly complicate things in this case
1009 template< class T, class cl_T, class fftw_T >
precallback_complex_to_complex_round_trip(data_pattern pattern,std::vector<size_t> lengths,size_t batch,layout::buffer_layout_t layout)1010 void precallback_complex_to_complex_round_trip( data_pattern pattern,
1011 									std::vector<size_t> lengths, size_t batch,
1012 									layout::buffer_layout_t layout )
1013 {
1014 	placeness::placeness_t placeness = placeness::in_place;
1015 
1016 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
1017 		NULL, NULL,	batch, 0, 0,
1018 		cl_layout(layout), cl_layout(layout),
1019 		cl_placeness( placeness ) );
1020 
1021 	buffer<T> expected( lengths.size(), &lengths[0], NULL, batch, 0, layout, CLFFT_OUTOFPLACE );
1022 
1023 	if( pattern == sawtooth )
1024 	{
1025 		test_fft.set_input_to_sawtooth( 1.0f );
1026 		expected.set_all_to_sawtooth( 1.0f );
1027 	}
1028 	else if( pattern == value )
1029 	{
1030 		test_fft.set_input_to_value( 2.0f, 2.5f );
1031 		expected.set_all_to_value( 2.0f, 2.5f );
1032 	}
1033 	else if( pattern == impulse )
1034 	{
1035 		test_fft.set_input_to_impulse();
1036 		expected.set_all_to_impulse();
1037 	}
1038 	else if( pattern == erratic )
1039 	{
1040 		test_fft.set_input_to_random();
1041 		expected.set_all_to_random_data( 10, super_duper_global_seed );
1042 	}
1043 	else
1044 	{
1045 		throw std::runtime_error( "invalid pattern type in complex_to_complex_round_trip()" );
1046 	}
1047 
1048 	// if we're starting with unequal data, we're destined for failure
1049 	EXPECT_EQ( true, test_fft.input_buffer() == expected );
1050 
1051 	test_fft.set_input_precallback();
1052 
1053 	//precallback user data
1054 	buffer<T> userdata( lengths.size(), &lengths[0], NULL, batch, 0, layout::real, CLFFT_OUTOFPLACE);
1055 	userdata.set_all_to_random_data(lengths[0], 10);
1056 
1057 	expected *= userdata;
1058 
1059 	test_fft.set_forward_transform();
1060 	test_fft.transform();
1061 
1062 	// confirm that we actually did something
1063 	bool stash_suppress_output = suppress_output;
1064 	suppress_output = true;
1065 	EXPECT_EQ( false, test_fft.result() == expected );
1066 	suppress_output = stash_suppress_output;
1067 
1068 	test_fft.refresh_plan();
1069 
1070 	test_fft.set_backward_transform();
1071 	test_fft.transform();
1072 
1073 	EXPECT_EQ( true, test_fft.result() == expected );
1074 }
1075 
1076 /*****************************************************/
1077 /*****************************************************/
1078 // dimension is inferred from lengths.size()
1079 // tightly packed is inferred from strides.empty()
1080 template< class T, class cl_T, class fftw_T >
real_to_complex_round_trip(data_pattern pattern,std::vector<size_t> lengths,size_t batch)1081 void real_to_complex_round_trip( data_pattern pattern,
1082 								 std::vector<size_t> lengths, size_t batch )
1083 {
1084 	placeness::placeness_t placeness = placeness::in_place;
1085 
1086 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
1087 		NULL, NULL,	batch, 0, 0,
1088 		cl_layout(layout::real), cl_layout(layout::hermitian_interleaved),
1089 		cl_placeness( placeness ) );
1090 
1091 	buffer<T> expected( lengths.size(), &lengths[0], NULL, batch, 0, layout::real, CLFFT_OUTOFPLACE );
1092 
1093 	if( pattern == sawtooth )
1094 	{
1095 		test_fft.set_input_to_sawtooth( 1.0f );
1096 		expected.set_all_to_sawtooth( 1.0f );
1097 	}
1098 	else if( pattern == value )
1099 	{
1100 		test_fft.set_input_to_value( 2.0f );
1101 		expected.set_all_to_value( 2.0f );
1102 	}
1103 	else if( pattern == impulse )
1104 	{
1105 		test_fft.set_input_to_impulse();
1106 		expected.set_all_to_impulse();
1107 	}
1108 	else if( pattern == erratic )
1109 	{
1110 		test_fft.set_input_to_random();
1111 		expected.set_all_to_random_data( 10, super_duper_global_seed );
1112 	}
1113 	else
1114 	{
1115 		throw std::runtime_error( "invalid pattern type in real_to_complex_round_trip()" );
1116 	}
1117 
1118 	// if we're starting with unequal data, we're destined for failure
1119 	EXPECT_EQ( true, test_fft.input_buffer() == expected );
1120 
1121 	test_fft.transform();
1122 
1123 	// confirm that we actually did something
1124 	bool stash_suppress_output = suppress_output;
1125 	suppress_output = true;
1126 	EXPECT_EQ( false, test_fft.result() == expected );
1127 	suppress_output = stash_suppress_output;
1128 
1129 	test_fft.swap_layouts();
1130 	test_fft.transform();
1131 
1132 	EXPECT_EQ( true, test_fft.result() == expected );
1133 }
1134 
1135 /*****************************************************/
1136 /*****************************************************/
1137 // dimension is inferred from lengths.size()
1138 // tightly packed is inferred from strides.empty()
1139 template< class T, class cl_T, class fftw_T >
precallback_real_to_complex_round_trip(data_pattern pattern,std::vector<size_t> lengths,size_t batch)1140 void precallback_real_to_complex_round_trip( data_pattern pattern,
1141 								 std::vector<size_t> lengths, size_t batch )
1142 {
1143 	placeness::placeness_t placeness = placeness::in_place;
1144 
1145 	clfft<T, cl_T> test_fft( static_cast<clfftDim>(lengths.size()), &lengths[0],
1146 		NULL, NULL,	batch, 0, 0,
1147 		cl_layout(layout::real), cl_layout(layout::hermitian_interleaved),
1148 		cl_placeness( placeness ) );
1149 
1150 	buffer<T> expected( lengths.size(), &lengths[0], NULL, batch, 0, layout::real, CLFFT_OUTOFPLACE );
1151 
1152 	if( pattern == sawtooth )
1153 	{
1154 		test_fft.set_input_to_sawtooth( 1.0f );
1155 		expected.set_all_to_sawtooth( 1.0f );
1156 	}
1157 	else if( pattern == value )
1158 	{
1159 		test_fft.set_input_to_value( 2.0f );
1160 		expected.set_all_to_value( 2.0f );
1161 	}
1162 	else if( pattern == impulse )
1163 	{
1164 		test_fft.set_input_to_impulse();
1165 		expected.set_all_to_impulse();
1166 	}
1167 	else if( pattern == erratic )
1168 	{
1169 		test_fft.set_input_to_random();
1170 		expected.set_all_to_random_data( 10, super_duper_global_seed );
1171 	}
1172 	else
1173 	{
1174 		throw std::runtime_error( "invalid pattern type in real_to_complex_round_trip()" );
1175 	}
1176 
1177 	// if we're starting with unequal data, we're destined for failure
1178 	EXPECT_EQ( true, test_fft.input_buffer() == expected );
1179 
1180 	test_fft.set_input_precallback();
1181 
1182 	//precallback user data
1183 	buffer<T> userdata( lengths.size(), &lengths[0], NULL, batch, 0, layout::real, CLFFT_OUTOFPLACE);
1184 	userdata.set_all_to_random_data(lengths[0], 10);
1185 
1186 	expected *= userdata;
1187 
1188 	test_fft.transform();
1189 
1190 	// confirm that we actually did something
1191 	bool stash_suppress_output = suppress_output;
1192 	suppress_output = true;
1193 	EXPECT_EQ( false, test_fft.result() == expected );
1194 	suppress_output = stash_suppress_output;
1195 
1196 	test_fft.swap_layouts();
1197 	test_fft.transform();
1198 
1199 	EXPECT_EQ( true, test_fft.result() == expected );
1200 }
1201