
#include <iostream>
#include "src/t_sne/tsne.h"
#include <random>
#include "RunDataLite.h"



void generateRandomData(const size_t& N, const size_t& D, double* X);
double euclidenDistance(double* y1, double* y2, int D);
int main(int argv, char* argc[]) {
	int amountOfSolutions = 1000;
	int amountOfBits = 1600;
	bool log = false;
	std::string filepath("generated.metalog");
	if (argv > 1) {
		std::cout << argc[1] << std::endl;
		filepath = argc[1];
		
	}

	RunDataLite* data = new RunDataLite(filepath);
	if (data->badFile()) return -1;
	data->solutionVec.erase(data->solutionVec.begin());

	//N -> amount of dataPoints 
	//D -> Dimension of DataPoints
	size_t N = data->solutionVec.size(), D = data->solutionVec[0].bitVec.size();
	std::cout << "N:" << N << " D:" << D << std::endl;
	double* X = new double[N * D];
	int nD = 0;
	for (int n = 0; n < N; n++) {
		const SolutionPointData& sol = data->solutionVec[n];
		if(log)std::cout << "[";
		for (int d = 0; d < D; d++) {
			X[ nD + d] = sol.bitVec[d]?1.0:0.0;
			if (log)std::cout << (sol.bitVec[d] ? "1" : "0");
		}
		if(log)std::cout << "]" << std::endl;
		nD += D;
	}
	if (log) {
		std::cout << std::endl << "Second:" << std::endl << std::endl;
		nD = 0;
		for (int n = 0; n < N; n++) {
			std::cout << "[";
			for (int d = 0; d < D; d++) {
				std::cout << (X[nD + d]);
			}
			std::cout << "]" << std::endl;
			nD += D;
		}
		std::cout << std::endl << "End:" << std::endl << std::endl;
	}



	//no_dims -> dimension of target 
	size_t no_dims = 2;
	double* Y = new double[N * no_dims];
	//Perplexity and theta
	double perplexity = 20;
	double theta = 0;
	//learnig rate epsillon;
	double eta = 200;
	//Random 
	int rand_seed = 17235761;
	bool skip_random_init = false;
	//Iter changes
	int max_iter = 750, stop_lying_iter = 250, mom_switch_iter = 100;
	TSNE::run(X, N, D, Y, no_dims, perplexity, theta, eta, rand_seed, skip_random_init, max_iter, stop_lying_iter, mom_switch_iter);
	std::cout << "Finished:" << std::endl;
	for (size_t i = 0; i < N; i++) {
		std::cout << Y[i * no_dims] << ", " << Y[i * no_dims + 1] << ", " << data->solutionVec[i].objectiveFunction << std::endl;
	}

	return 0;
}
















void generateRandomData(const size_t& N, const size_t& D, double* X)
{
	//init rnd
	std::random_device rd;  //Will be used to obtain a seed for the random number engine
	std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
	std::uniform_real_distribution<double> doubleDistr(0.0, 1.0);
	//GenerateData
	for (size_t i = 0; i < N; i++) {
		double rnd = doubleDistr(gen);
		for (size_t j = 0; j < D; j++) {
			X[i * D + j] = (doubleDistr(gen) < rnd ? 1.0 : 0.0);
		}
	}
	if (N < 20) {
		for (size_t i = 0; i < N; i++) {
			std::cout << "[";
			for (size_t j = 0; j < D; j++) {
				std::cout << (X[i * D + j] != 0.0 ? "1" : "0");
			}
			std::cout << "]" << std::endl;
		}
	}
}
double euclidenDistance( double* y1, double* y2, int D) {
	double sum = 0.0;
	std::cout << "[";
	for (size_t j = 0; j < D; j++) {
		std::cout << (y1[j] != 0.0 ? "1" : "0");
	}
	std::cout << "]" << std::endl;
	std::cout << "[";
	for (size_t j = 0; j < D; j++) {
		std::cout << (y2[j] != 0.0 ? "1" : "0");
	}
	std::cout << "]" << std::endl;
	for (int i = 0; i < D; i++) {
		sum += (y1[i] - y2[i]) * (y1[i] - y2[i]);
	}
	return std::sqrt(sum);
}