import pickle
import numpy as np
from timeit import default_timer as timer
import matplotlib.pyplot as plt

from acceleration import *
import analysis.utils as utils


timescale = 10 # ms, approximate time per attempt
massive = True # whether all particles are massive

functions = [bruteForce, bruteForceNumba, bruteForceNumbaOptimized, bruteForceCPP, barnesHutCPP]
labels = ['Brute force', 'Brute force Numba', 'Brute force Numba opt.', 'Brute force [C++]', 'Barnes-Hut [C++]']
styles = ['solid', 'dashed', 'solid', 'dashed', 'solid']
colours = ['cornflowerblue', 'cornflowerblue', 'darkorange', 'darkorange', 'black']
if not massive: #do not evaluate barnes hut
	functions, labels, styles, colours = functions[:-1], labels[:-1], styles[:-1], colours[:-1]


timess = []

for i in range(len(functions)):
	n = 10 #First data point
	# Run attempts with multiple iterations each
	iterations = 1000
	attempts = 6
	timess.append([])
	while(True):
		# Evaluate the performance
		localTimes = []
		for _ in range(attempts):
			# Initialize random data
			r_vec = np.random.rand(n, 3).astype(np.float64)
			if massive:
				m_vec = np.random.rand(n).astype(np.float64)
			else:
				m_vec = np.zeros(n).astype(np.float64)
				m_vec[0] = 1
			start = timer()
			for _ in range(iterations):
				functions[i](r_vec, m_vec)
			stop = timer()
			localTimes.append((stop - start)*1000/iterations) #in ms
		# Calculate mean and error
		# Discard high times since these are likely due to interferences
		localTimes = np.sort(localTimes)
		localTimes = localTimes[:attempts-2]
		print(localTimes, iterations)
		error = np.std(localTimes)/np.sqrt(attempts-1)
		timess[i].append([n, np.mean(localTimes), error])

		# Recalculate how many iterations would have been sensible
		iterations = int(timescale/np.mean(localTimes))
		if iterations > 1000: iterations = 1000
		if iterations < 1: break;

		# Increase the number of points
		n *= 2

# Plot the results
f, ax = plt.subplots(1, 1,  figsize=(6, 4), sharey=True)

for times, label, style, colour in zip(timess, labels, styles, colours):
	times = np.array(times)
	ax.errorbar(times[:,0], times[:,1], yerr=times[:,2], 
		label=label, marker='+', linestyle=style, c=colour)

ax.loglog()
if massive:
	utils.setAxes(ax, x='Number of massive particles', y='Time / ms', 
	xcoords=(.7, -0.1), ycoords=(-0.1,.7))
else:
	utils.setAxes(ax, x='Number of massless particles', y='Time / ms', 
	xcoords=(.7, -0.1), ycoords=(-0.1,.7))
utils.stylizePlot([ax])
ax.legend()
ax.set_xlim((10, None))
plt.show()


file = open('data/performance.pickle', "wb")
pickle.dump(timess, file)



