#!/usr/bin/env python

import sys
import numpy

def array_print(name, data):
	if type_scalar == numpy.float16:
		a = ['{:#04x}'.format(h.astype(int)) for h in data.view(dtype=numpy.uint16)]
	else:
		a = [repr(x) for x in data]
	print 'fftval_t {}[{}] = {{ {} }};'.format(name, len(a), ', '.join(a))

def array_permute(data, radix = 2):
	logradix = int(numpy.log2(radix))
	term_mask = int(radix - 1)
#	num_term = int(numpy.log2(len(data)) / logradix)
	for i in xrange(0, len(data)):
		# Obtain permuted address
		i_left = i
		permuted = 0
		cur_fft_size = radix
		while cur_fft_size <= len(data):
			permuted = (permuted << logradix) | (i_left & term_mask)
			i_left >>= logradix
			cur_fft_size <<= logradix
		# Permute only once and when addresses are different
		if i < permuted:
			tmp = data[i]
			data[i] = data[permuted]
			data[permuted] = tmp

fft_size = 1024
type_scalar = numpy.float16
permute = True

if len(sys.argv) > 1:
	type_scalar = {
		'16' : numpy.float16,
		'32' : numpy.float32,
		'64' : numpy.float64 }.get(sys.argv[1].strip(), None)
	if type_scalar == None:
		sys.exit('Invalid datatype')

if len(sys.argv) > 2:
	fft_size = sys.argv[2].strip()
	if not fft_size.isdigit():
		sys.exit('Invalid FFT size')
	fft_size = int(fft_size)

numpy.random.seed(seed=0)

print '#include "fft_const.h"'

# Generate input data
input_real = numpy.random.uniform(size=fft_size).astype(type_scalar)
input_imag = numpy.random.uniform(size=fft_size).astype(type_scalar)

# Compute reference FFT output
type_cmplx = numpy.complex128 if (type_scalar == numpy.float64) else numpy.complex64
input_cmplx = input_real.astype(type_cmplx)
input_cmplx.imag = input_imag
output_cmplx = numpy.fft.fft(input_cmplx)

if permute:
	array_permute(input_real)
	array_permute(input_imag)

array_print('input_data_real', input_real)
array_print('input_data_imag', input_imag)

output_real = output_cmplx.real.astype(type_scalar)
output_imag = output_cmplx.imag.astype(type_scalar)

array_print('output_data_real', output_real)
array_print('output_data_imag', output_imag)

# Generate twiddle factors (TFs)
# Negate sine since twiddle factor angles are generated *clockwise* from 0
rad = [(2.0 * numpy.pi * (float(i) / fft_size)) for i in xrange(fft_size)]
tf_real = numpy.cos(rad).astype(type_scalar)
tf_imag = -numpy.sin(rad).astype(type_scalar)

array_print('tf_real', tf_real)
array_print('tf_imag', tf_imag)
