/*******************************************************************
Author: David Ge (dge893@gmail.com, aka Wei Ge)
Last modified: 11/21/2020
Allrights reserved by David Ge

base class for time advancement estimation module
********************************************************************/
#include "TimeTssBase.h"
#include "../FileUtil/fileutil.h"
#include "../ProcessMonitor/ProcessMonitor.h"
#include "../ProcessMonitor/workProcess.h"

#include <thread>

#include <boost/multiprecision/cpp_dec_float.hpp>

bool voidReport(){ return false; }
TimeTssBase::TimeTssBase()
{
	GehP = GhhP = GeeP = GheP = NULL;
	space = NULL;
	H = E = curlH = curlE = NULL; // workH = workE = NULL;
	currentTime = 0.0;
	tIndex = 0;
	reporter = NULL;
	operationCanceled = voidReport;
}

TimeTssBase::~TimeTssBase()
{
	cleanup();
}
void TimeTssBase::cleanup()
{
	//
	if (GehP != NULL)
	{
		free(GehP); GehP = NULL;
	}
	if (GhhP != NULL)
	{
		free(GhhP); GhhP = NULL;
	}
	if (GeeP != NULL)
	{
		free(GeeP); GeeP = NULL;
	}
	if (GheP != NULL)
	{
		free(GheP); GheP = NULL;
	}
	//
	if (H != NULL)
	{
		FreeMemory(H); H = NULL;
	}
	if (E != NULL)
	{
		FreeMemory(E); E = NULL;
	}
	if (curlH != NULL)
	{
		FreeMemory(curlH); curlH = NULL;
	}
	if (curlE != NULL)
	{
		FreeMemory(curlE); curlE = NULL;
	}
}
void TimeTssBase::onSettingSimParams()
{
	cellCount = (pams->nx + 1)*(pams->ny + 1)*(pams->nz + 1);
}
int TimeTssBase::initializeTimeModule(Space *s, SimStruct *pams0, FieldSourceTss *src)
{
	using namespace boost::multiprecision;
	int ret = ERR_OK;
	puts("\r\nCalculating update coefficients...");
	pams = pams0;
	onSettingSimParams();
	fieldMemorySize = cellCount*sizeof(Point3Dstruct);
	if (src != NULL)
	{
		if (!src->Initialized())
		{
			return ERR_SRC_NOT_INIT;
		}
	}
	space = s;
	source = src;
	cpp_dec_float_100 *G_ehP = (cpp_dec_float_100 *)malloc((pams->kmax + 1)*sizeof(cpp_dec_float_100));
	cpp_dec_float_100 *G_hhP = (cpp_dec_float_100 *)malloc((pams->kmax + 1)*sizeof(cpp_dec_float_100));
	cpp_dec_float_100 *G_eeP = (cpp_dec_float_100 *)malloc((pams->kmax + 1)*sizeof(cpp_dec_float_100));
	cpp_dec_float_100 *G_heP = (cpp_dec_float_100 *)malloc((pams->kmax + 1)*sizeof(cpp_dec_float_100));
	//
	GehP = (double*)malloc((pams->kmax + 1)*sizeof(double));
	GhhP = (double*)malloc((pams->kmax + 1)*sizeof(double));
	GeeP = (double*)malloc((pams->kmax + 1)*sizeof(double));
	GheP = (double*)malloc((pams->kmax + 1)*sizeof(double));
	if (G_ehP == NULL || G_hhP == NULL || G_eeP == NULL || G_heP == NULL || GehP == NULL || GhhP == NULL || GeeP == NULL || GheP == NULL)
	{
		ret = ERR_OUTOFMEMORY;
	}
	else
	{
		printf("\r\nUpdate coefficients allocated. Array size:%u ", pams->kmax + 1);
		for (unsigned int k = 0; k <= pams->kmax; k++)
		{
			G_ehP[k] = G_hhP[k] = G_eeP[k] = G_heP[k] = 0.0;
			GehP[k]  = GhhP[k]  = GeeP[k]  = GheP[k]  = 0.0;
		}
	}
	if (ret == ERR_OK)
	{
		/*
		p[h=0..2k_max+2,i=0..2k_max+2]=p_i^{h}
		q[h=0..2k_max+2,i=0..2k_max+2]=q_i^{h}
		*/
		size_t pMax = 2 * pams->kmax + 3; // 0 ... 2kmax+2
		size_t pMax2 = pMax * pMax;
		//p_i^{h}
#define Idx_ih(i, h) ((h)*pMax+(i))
		cpp_dec_float_100 *p = (cpp_dec_float_100 *)malloc(pMax2*sizeof(cpp_dec_float_100));
		cpp_dec_float_100 *q = (cpp_dec_float_100 *)malloc(pMax2*sizeof(cpp_dec_float_100));
		cpp_dec_float_100 *dtR = (cpp_dec_float_100 *)malloc(pMax*sizeof(cpp_dec_float_100));
		cpp_dec_float_100 *dsR = (cpp_dec_float_100 *)malloc(pMax*sizeof(cpp_dec_float_100));
		if (p == NULL || q == NULL || dtR == NULL || dsR == NULL)
		{
			ret = ERR_OUTOFMEMORY;
		}
		if (ret == ERR_OK)
		{
			cpp_dec_float_100 gde = pams->sie;
			cpp_dec_float_100 geps = pams->eps;
			cpp_dec_float_100 gmu = pams->mu;
			cpp_dec_float_100 gdm = pams->sim;
			cpp_dec_float_100 g1 = 1.0;
			cpp_dec_float_100 f;
			//values for k=0
			cpp_dec_float_100 dt2 = 1.0;
			cpp_dec_float_100 XN = 0.0;
			cpp_dec_float_100 X = 1.0;
			cpp_dec_float_100 ds2 = 1.0;
			for (unsigned int k = 0; k < pMax2; k++)
			{
				p[k] = 0.0; q[k] = 0.0;
			}
			//p_0^0=1, q_0^0 = 1
			p[0] = 1.0; q[0] = 1.0;
			for (unsigned int k = 0; k < pMax; k++)
			{
				f = dt2 / X;
				dtR[k] = f; //dt^k/k!
				dsR[k] = ds2; //ds^k
				//prepare for k+1
				XN = XN + 1.0;
				X = X * XN;
				dt2 = dt2 * pams->dt;
				ds2 = ds2 * pams->ds;
			}
			/*
			p_0^{1} =1/ε,p_1^{1} =-σ/ε
			q_0^{1} =-1/μ,q_1^{1} =-σ_m/μ
			*/
			p[Idx_ih(0, 1)] = g1 / geps; p[Idx_ih(1, 1)] = -gde / geps;
			q[Idx_ih(0, 1)] = -g1 / gmu; q[Idx_ih(1, 1)] = -gdm / gmu;
			/*
			p_0^{2k}  =q_0^{1}  p_0^{2k-1}
			p_2k^{2k} =p_(2k-1)^{2k-1}  p_1^{1}
			q_0^{2k}  =p_0^{1}  q_0^{2k-1}
			q_2k^{2k} =q_(2k-1)^{2k-1}  q_1^{1}

			p_0^{2k+1}      =p_0^{1}  p_0^{2k}
			p_(2k+1)^{2k+1} =p_2k^{2k}  p_1^{1}
			q_0^{2k+1}      =q_0^{1}  q_0^{2k}
			q_(2k+1)^{2k+1} =q_2k^{2k}  q_1^{1}
			*/
			//from (0,1), (1,1) get
			//(0,2)...(0,2kmax+2); (2,2) ... (2kmax+2,2kmax+2)
			//(0,3)...(0,2kmax+1); (3,3) ... (2kmax+1,2kmax+1)
			for (unsigned int k = 1; k <= pams->kmax + 1; k++)
			{
				p[Idx_ih(0, 2 * k)] = q[Idx_ih(0, 1)] * p[Idx_ih(0, 2 * k - 1)];
				q[Idx_ih(0, 2 * k)] = p[Idx_ih(0, 1)] * q[Idx_ih(0, 2 * k - 1)];
				p[Idx_ih(2 * k, 2 * k)] = p[Idx_ih(2 * k - 1, 2 * k - 1)] * p[Idx_ih(1, 1)];
				q[Idx_ih(2 * k, 2 * k)] = q[Idx_ih(2 * k - 1, 2 * k - 1)] * q[Idx_ih(1, 1)];
				if (k <= pams->kmax)
				{
					p[Idx_ih(0, 2 * k + 1)] = p[Idx_ih(0, 1)] * p[Idx_ih(0, 2 * k)];
					q[Idx_ih(0, 2 * k + 1)] = q[Idx_ih(0, 1)] * q[Idx_ih(0, 2 * k)];
					p[Idx_ih(2 * k + 1, 2 * k + 1)] = p[Idx_ih(2 * k, 2 * k)] * p[Idx_ih(1, 1)];
					q[Idx_ih(2 * k + 1, 2 * k + 1)] = q[Idx_ih(2 * k, 2 * k)] * q[Idx_ih(1, 1)];
				}
			}
			/*
			p_(2i+1)^{2k} =q_1^{1}  p_2i^{2k-1} +p_0^{1}  p_(2i+1)^{2k-1} ;    i=0,1,…,k-1;k_max+1≥k>0
			q_(2i+1)^{2k} =p_1^{1}  q_2i^{2k-1} +q_0^{1}  q_(2i+1)^{2k-1} ;    i=0,1,…,k-1;k_max+1≥k>0
			p_(2i+2)^{2k} =p_1^{1}  p_(2i+1)^{2k-1} +q_0^{1}  p_(2i+2)^{2k-1} ;i=0,1,…,k-2;k_max+1≥k>1
			q_(2i+2)^{2k} =q_1^{1}  q_(2i+1)^{2k-1} +p_0^{1}  q_(2i+2)^{2k-1} ;i=0,1,…,k-2;k_max+1≥k>1
			*/
			for (unsigned int k = 1; k <= pams->kmax + 1; k++)
			{
				for (unsigned int i = 0; i < k; i++)
				{
					p[Idx_ih(2 * i + 1, 2 * k)] = q[Idx_ih(1, 1)] * p[Idx_ih(2 * i, 2 * k - 1)] + p[Idx_ih(0, 1)] * p[Idx_ih(2 * i + 1, 2 * k - 1)];
					q[Idx_ih(2 * i + 1, 2 * k)] = p[Idx_ih(1, 1)] * q[Idx_ih(2 * i, 2 * k - 1)] + q[Idx_ih(0, 1)] * q[Idx_ih(2 * i + 1, 2 * k - 1)];
					if (k>1 && i < k - 1)
					{
						p[Idx_ih(2 * i + 2, 2 * k)] = p[Idx_ih(1, 1)] * p[Idx_ih(2 * i + 1, 2 * k - 1)] + q[Idx_ih(0, 1)] * p[Idx_ih(2 * i + 2, 2 * k - 1)];
						q[Idx_ih(2 * i + 2, 2 * k)] = q[Idx_ih(1, 1)] * q[Idx_ih(2 * i + 1, 2 * k - 1)] + p[Idx_ih(0, 1)] * q[Idx_ih(2 * i + 2, 2 * k - 1)];
					}
				}
				if (k <= pams->kmax)
				{
					/*
					p_(2i-1)^{2k+1} =p_1^{1}  p_(2i-2)^{2k} +q_0^{1}  p_(2i-1)^{2k}
					p_2i    ^{2k+1} =q_1^{1}  p_(2i-1)^{2k} +p_0^{1}  p_2i^{2k}
					q_(2i-1)^{2k+1} =q_1^{1}  q_(2i-2)^{2k} +p_0^{1}  q_(2i-1)^{2k}
					q_2i    ^{2k+1} =p_1^{1}  q_(2i-1)^{2k} +q_0^{1}  q_2i^{2k}
					i=1,2,…,k;k≥1
					*/
					for (unsigned int i = 1; i <= k; i++)
					{
						p[Idx_ih(2 * i - 1, 2 * k + 1)] = p[Idx_ih(1, 1)] * p[Idx_ih(2 * i - 2, 2 * k)] + q[Idx_ih(0, 1)] * p[Idx_ih(2 * i - 1, 2 * k)];
						q[Idx_ih(2 * i - 1, 2 * k + 1)] = q[Idx_ih(1, 1)] * q[Idx_ih(2 * i - 2, 2 * k)] + p[Idx_ih(0, 1)] * q[Idx_ih(2 * i - 1, 2 * k)];
						p[Idx_ih(2 * i, 2 * k + 1)] = q[Idx_ih(1, 1)] * p[Idx_ih(2 * i - 1, 2 * k)] + p[Idx_ih(0, 1)] * p[Idx_ih(2 * i, 2 * k)];
						q[Idx_ih(2 * i, 2 * k + 1)] = p[Idx_ih(1, 1)] * q[Idx_ih(2 * i - 1, 2 * k)] + q[Idx_ih(0, 1)] * q[Idx_ih(2 * i, 2 * k)];
					}
				}
			}
			////calculate G_e^h, G_h^h, G_h^e, G_e^e///////////////////////////////
			cpp_dec_float_100 a, b, c;
			/*
			i=0,1,...,kmax
			G_e^h (i,∆_t)=∑_(k=i)^(k_max)〖C_e^h (k,i,∆_t ) 〗
			G_h^h (i,∆_t)=∑_(k=i)^(k_max)〖C_h^h (k,i,∆_t ) 〗
			G_h^e (i,∆_t)=∑_(k=i)^(k_max)〖C_h^e (k,i,∆_t ) 〗
			G_e^e (i,∆_t)=∑_(k=i)^(k_max)〖C_e^e (k,i,∆_t ) 〗
			//
			sum k=i,i+1,...,kmax
			start from (∆_t^(2i+1))/(2i+1)! go up
			-------------------------------------
			C_e^h (k,i,∆_t )= ((∆_t^(2k+1))/(2k+1)! q_0^{2k+1}                                        ,i=k
							  (∆_t^2k)/(2k)! q_(2(k-i)-1)^{2k} + (∆_t^(2k+1))/(2k+1)! q_2(k-i)^{2k+1} ,0≤i<k
			//
			C_h^e (k,i,∆_t )= ((∆_t^(2k+1))/(2k+1)! p_0^{2k+1}                                        ,i=k
							  (∆_t^2k)/(2k)! p_(2(k-i)-1)^{2k} + (∆_t^(2k+1))/(2k+1)! p_2(k-i)^{2k+1} ,0≤i<k
			====================
			C_h^h (k,i,∆_t )=(∆_t^2k)/(2k)! q_2(k-i)^{2k} +(∆_t^(2k+1))/(2k+1)! q_(2(k-i)+1)^{2k+1}
			C_e^e (k,i,∆_t )=(∆_t^2k)/(2k)! p_2(k-i)^{2k} +(∆_t^(2k+1))/(2k+1)! p_(2(k-i)+1)^{2k+1}
			--------------------------------
			*/
			for (unsigned int i = 0; i <= pams->kmax; i++)
			{
				G_ehP[i] = 0.0; G_hhP[i] = 0.0; G_eeP[i] = 0.0; G_heP[i] = 0.0;
				for (unsigned int k = i; k <= pams->kmax; k++)
				{
					a = q[Idx_ih(2 * (k - i), 2 * k)];
					b = p[Idx_ih(2 * (k - i), 2 * k)];
					G_hhP[i] += dtR[2*k] * a;
					G_eeP[i] += dtR[2*k] * b;
					//
					a = q[Idx_ih(2 * (k - i)+1, 2 * k+1)];
					b = p[Idx_ih(2 * (k - i)+1, 2 * k+1)];
					G_hhP[i] += dtR[2 * k+1] * a;
					G_eeP[i] += dtR[2 * k+1] * b;
					//
					if (k == i)
					{
						a = q[Idx_ih(0, 2 * k + 1)];
						b = p[Idx_ih(0, 2 * k + 1)];
						G_ehP[i] += dtR[2 * k + 1] * a;
						G_heP[i] += dtR[2 * k + 1] * b;
					}
					else
					{
						a = q[Idx_ih(2 * (k - i) - 1, 2 * k)];
						b = p[Idx_ih(2 * (k - i) - 1, 2 * k)];
						G_ehP[i] += dtR[2 * k] * a;
						G_heP[i] += dtR[2 * k] * b;
						//
						a = q[Idx_ih(2 * (k - i), 2 * k + 1)];
						b = p[Idx_ih(2 * (k - i), 2 * k + 1)];
						G_ehP[i] += dtR[2 * k+1] * a;
						G_heP[i] += dtR[2 * k+1] * b;
					}
				}
			}
			/*
			G_h^h (i,∆_t ) ∇ ̅^{2i} ×H+G_e^h (i,∆_t ) ∇ ̅^{2i+1} ×E
			G_e^e (i,∆_t ) ∇ ̅^{2i} ×E+G_h^e (i,∆_t ) ∇ ̅^{2i+1} ×H
			*/
			for (unsigned int i = 0; i <= pams->kmax; i++)
			{
				G_ehP[i] = G_ehP[i] / dsR[2 * i + 1];
				G_heP[i] = G_heP[i] / dsR[2 * i + 1];
				G_hhP[i] = G_hhP[i] / dsR[2 * i];
				G_eeP[i] = G_eeP[i] / dsR[2 * i];
			}
			for (unsigned int i = 0; i <= pams->kmax; i++)
			{
				GehP[i] = G_ehP[i].convert_to<double>();
				GheP[i] = G_heP[i].convert_to<double>();
				GhhP[i] = G_hhP[i].convert_to<double>();
				GeeP[i] = G_eeP[i].convert_to<double>();
			}
			free(G_ehP); free(G_heP); free(G_hhP); free(G_eeP);
			if (source != NULL)
			{
				if (ret == ERR_OK)
				{
					unsigned int emMax = source->GetemMax(); //2 * kmax + 3;
					size_t emMax2 = emMax*emMax;
					cpp_dec_float_100 *e = (cpp_dec_float_100 *)malloc(emMax2*sizeof(cpp_dec_float_100));
					cpp_dec_float_100 *m = (cpp_dec_float_100 *)malloc(emMax2*sizeof(cpp_dec_float_100));
					size_t t,t1;
					for (t = 0; t < emMax2; t++)
					{
						e[t] = 0.0; m[t] = 0.0;
					}
					/*
					Eq. (16), (17)
					e_0^{0} =-1/ε
					m_0^{0} =-1/μ
					*/
					e[I_ih(0, 0)] = -1.0 / pams->eps;
					m[I_ih(0, 0)] = -1.0 / pams->mu;
					/*
					Eq. (18)
					e_2(k-i)^{2i} =p_(2(k-i))^{2k}  e_0^{0} ,
					m_2(k-i)^{2i} =q_(2(k-i))^{2k}  m_0^{0} ,
					i=0,1,2,…,k, k>0
					*/
					for (unsigned int k = 1; k <= pams->kmax + 1; k++)
					{
						for (unsigned int i = 0; i <= k; i++)
						{
							//0...2kmax+2
							t = I_ih(2 * (k - i), 2 * i); //[2kmax+2, (2kmax), ..., 0], {0, 2, ..., 2kmax+2}
							e[t] = p[Idx_ih(2 * (k - i), 2 * k)] * e[I_ih(0, 0)];
							m[t] = q[Idx_ih(2 * (k - i), 2 * k)] * m[I_ih(0, 0)];
						}
					}
					/*
					Eq. (19)
					m_(2(k-i)+1)^{2i-1} =p_(2(k-i)+1)^{2k}  m_0^{0} ,
					e_(2(k-i)+1)^{2i-1} =q_(2(k-i)+1)^{2k}  e_0^{0} ,
					i=1,2,…,k,k>0
					*/
					for (unsigned int k = 1; k <= pams->kmax + 1; k++)
					{
						for (unsigned int i = 1; i <= k; i++)
						{
							t = I_ih(2 * (k - i) + 1, 2 * i - 1);//[2kmax+1,2kmax-1,...,1], {1,3,...,2kmax+1}
							m[t] = p[Idx_ih(2 * (k - i) + 1, 2 * k)] * m[I_ih(0, 0)];
							e[t] = q[Idx_ih(2 * (k - i) + 1, 2 * k)] * e[I_ih(0, 0)];
						}
					}
					/*
					Eq. (26)
					e_(2(k-i)-1)^{2i} =p_(2(k-i)-1)^{2k-1}  e_0^{0} ,
					m_(2(k-i)-1)^{2i} =q_(2(k-i)-1)^{2k-1}  m_0^{0} ,
					i=0,1,2,…,k-1, k>0
					Eq. (27)
					m_(2(k-i-1))^{2i+1} =p_(2(k-i-1))^{2k-1}  m_0^{0} ,
					e_(2(k-i-1))^{2i+1} =q_(2(k-i-1))^{2k-1}  e_0^{0} ,
					i=0,1,2,…,k-1, k>0
					*/
					for (unsigned int k = 1; k <= pams->kmax + 1; k++)
					{
						for (unsigned int i = 0; i < k; i++)
						{
							t = I_ih(2 * (k - i) - 1, 2 * i);//[2kmax+1,2kmax-1,...,1],{0,2,...,2kmax+2}
							t1 = Idx_ih(2 * (k - i) - 1, 2 * k - 1);
							e[t] = p[t1] * e[I_ih(0, 0)];
							m[t] = q[t1] * m[I_ih(0, 0)];
							t = I_ih(2 * (k - i - 1), 2 * i + 1);//[2kmax,2kmax-2,...,0],{1,2,...,2kmax+1}
							t1 = Idx_ih(2 * (k - i - 1), 2 * k - 1);
							m[t] = p[t1] * m[I_ih(0, 0)];
							e[t] = q[t1] * e[I_ih(0, 0)];
						}
					}
					ret = source->onInitialized(e, m);
					free(e); free(m);
				}
			}
		}
		if (p != NULL) { free(p); p = NULL; }
		if (q != NULL) { free(q); q = NULL; }
	}
	if (ret == ERR_OK)
	{
		startThreads();
		ret = pml.initialize(pams);
	}
	if (ret == ERR_OK)
	{
		puts("\r\nFinished calculating update coefficients.");
	}
	return ret;
}
int TimeTssBase::initFields(FieldsSetter* f0)
{
	int ret = ERR_OK;
	puts("\r\nAllocating field memories...");
	//
	//all field memories used
	if (H != NULL)
	{
		FreeMemory(H); H = NULL;
	}
	if (E != NULL)
	{
		FreeMemory(E); E = NULL;
	}
	if (curlH != NULL)
	{
		FreeMemory(curlH); curlH = NULL;
	}
	if (curlE != NULL)
	{
		FreeMemory(curlE); curlE = NULL;
	}
	H = (Point3Dstruct *)AllocateMemory(fieldMemorySize);
	if (H == NULL)
	{
		ret = MEMRETLAST;
		if (ret == ERR_OK)
		{
			ret = ERR_OUTOFMEMORY;
		}
	}
	if (ret == ERR_OK)
	{
		E = (Point3Dstruct *)AllocateMemory(fieldMemorySize);
		if (E == NULL)
		{
			ret = MEMRETLAST;
			if (ret == ERR_OK)
			{
				ret = ERR_OUTOFMEMORY;
			}
		}
	}
	if (ret == ERR_OK)
	{
		curlH = (Point3Dstruct *)AllocateMemory(fieldMemorySize);
		if (curlH == NULL)
		{
			ret = MEMRETLAST;
			if (ret == ERR_OK)
			{
				ret = ERR_OUTOFMEMORY;
			}
		}
	}
	if (ret == ERR_OK)
	{
		curlE = (Point3Dstruct *)AllocateMemory(fieldMemorySize);
		if (curlE == NULL)
		{
			ret = MEMRETLAST;
			if (ret == ERR_OK)
			{
				ret = ERR_OUTOFMEMORY;
			}
		}
	}
	if (ret == ERR_OK)
	{
		size_t w = 0;
		double x = pams->xmin, y, z;
		puts("\r\nInitializing fields...");
		for (unsigned int i = 0; i <= pams->nx; i++)
		{
			y = pams->ymin;
			for (unsigned int j = 0; j <= pams->ny; j++)
			{
				z = pams->zmin;
				for (unsigned int k = 0; k <= pams->nz; k++)
				{
					if (f0 != NULL)
					{
						f0->SetFields(x, y, z, &(E[w]), &(H[w]));
					}
					else
					{
						E[w].x = 0.0;
						E[w].y = 0.0;
						E[w].z = 0.0;
						H[w].x = 0.0;
						H[w].y = 0.0;
						H[w].z = 0.0;
					}
					z += pams->ds;
					w++;
				}
				y += pams->ds;
			}
			x += pams->ds;
		}
	}
	return ret;
}

int TimeTssBase::writeCoefficientsToFile(char *file, unsigned int maxTimeSteps, double courantFactor, unsigned int dataFileSteps)
{
	int ret = ERR_OK;
	FILE *retFileHandle = 0;
	if (file != NULL)
	{
		ret = deleteFile(file);
		if (ret == ERR_OK)
		{
			ret = openTextfileWrite(file, &retFileHandle);
		}
	}
	else
	{
		ret = ERR_FILENAME_MISSING;
	}
	if (retFileHandle != 0)
	{
		unsigned int size = 1024;
		char buff[1024];
		sprintf_1(buff, size, "kmax=%u, time estimation order = 2(kmax+1)=%u \nds=%g, dt=%g, courant factor=%g, total time=%g, data file interval=%g\n", pams->kmax, 2 * (pams->kmax + 1), pams->ds, pams->dt, courantFactor, pams->dt*maxTimeSteps, pams->dt*dataFileSteps);
		writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		sprintf_1(buff, size, "material parameters: eps=%g, mu=%g, sigma_e=%g, sigma_h=%g\r\n", pams->eps, pams->mu, pams->sie, pams->sim);
		writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		////////////H/////////////////////////////////////////////
		sprintf_1(buff, size, "H=C.F.dJm+C.G.dJe+");
		writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		//Curl X H -> H
		for (unsigned int k = 0; k <= pams->kmax; k++)
		{
			if (k == 0)
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, "[%g]C2xH+", GhhP[k]);
				}
				else
				{
					sprintf_1(buff, size, "[%g,", GhhP[k]);
				}
			}
			else
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, " %g]C2xH+", GhhP[k]);
				}
				else
				{
					sprintf_1(buff, size, " %g,", GhhP[k]);
				}
			}
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		}
		//CE->H
		for (unsigned int k = 0; k <= pams->kmax; k++)
		{
			if (k == 0)
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, "[%g]C1xE\r\n", GehP[k]);
				}
				else
				{
					sprintf_1(buff, size, "[%g,", GehP[k]);
				}
			}
			else
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, " %g]C1xE\n", GehP[k]);
				}
				else
				{
					sprintf_1(buff, size, " %g,", GehP[k]);
				}
			}
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		}
		///////////////E///////////
		sprintf_1(buff, size, "\nE=C.U.dJe+C.W.dJm+");
		writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		//Curl X E -> E
		for (unsigned int k = 0; k <= pams->kmax; k++)
		{
			if (k == 0)
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, "[%g]C2xE+", GeeP[k]);
				}
				else
				{
					sprintf_1(buff, size, "[%g,", GeeP[k]);
				}
			}
			else
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, " %g]C2xE+", GeeP[k]);
				}
				else
				{
					sprintf_1(buff, size, " %g,", GeeP[k]);
				}
			}
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		}
		//CH->E
		for (unsigned int k = 0; k <= pams->kmax; k++)
		{
			if (k == 0)
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, "[%g]C1xH\n", GheP[k]);
				}
				else
				{
					sprintf_1(buff, size, "[%g,", GheP[k]);
				}
			}
			else
			{
				if (k == pams->kmax)
				{
					sprintf_1(buff, size, " %g]C1xH\n", GheP[k]);
				}
				else
				{
					sprintf_1(buff, size, " %g,", GheP[k]);
				}
			}
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
		}
		if (source != NULL)
		{
			double *f = source->GetJmH();
			double *g = source->GetJeH();
			double *u = source->GetJeE();
			double *w = source->GetJmE();
			unsigned int srcDim = source->GetsrcDim();
			unsigned int t = 0;
			//SH=============================================
			sprintf_1(buff, size, "\nF[ %u x %u ]=\n", srcDim, srcDim);
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
			t = 0;
			for (unsigned int i = 0; i < srcDim; i++)
			{
				for (unsigned int j = 0; j < srcDim; j++)
				{
					if (j == srcDim - 1)
					{
						sprintf_1(buff, size, " %g\n", f[t]);
					}
					else
					{
						sprintf_1(buff, size, " %g,\t", f[t]);
					}
					writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
					t++;
				}
			}
			sprintf_1(buff, size, " \nG[ %u x %u ]=\n", srcDim, srcDim);
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
			t = 0;
			for (unsigned int i = 0; i < srcDim; i++)
			{
				for (unsigned int j = 0; j < srcDim; j++)
				{
					if (j == srcDim - 1)
					{
						sprintf_1(buff, size, " %g\n", g[t]);
					}
					else
					{
						sprintf_1(buff, size, " %g,\t", g[t]);
					}
					writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
					t++;
				}
			}
			//SE=============================================
			sprintf_1(buff, size, "\nU[ %u x %u ]=\n", srcDim, srcDim);
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
			t = 0;
			for (unsigned int i = 0; i < srcDim; i++)
			{
				for (unsigned int j = 0; j < srcDim; j++)
				{
					if (j == srcDim - 1)
					{
						sprintf_1(buff, size, " %g\n", u[t]);
					}
					else
					{
						sprintf_1(buff, size, " %g,\t", u[t]);
					}
					writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
					t++;
				}
			}
			sprintf_1(buff, size, "\nW[ %u x %u ]=\n", srcDim, srcDim);
			writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
			t = 0;
			for (unsigned int i = 0; i < srcDim; i++)
			{
				for (unsigned int j = 0; j < srcDim; j++)
				{
					if (j == srcDim - 1)
					{
						sprintf_1(buff, size, " %g\n", w[t]);
					}
					else
					{
						sprintf_1(buff, size, " %g,\t", w[t]);
					}
					writefile(retFileHandle, buff, (unsigned int)strnlen_0(buff, size));
					t++;
				}
			}
		}//source
		if (pml.usePML())
		{
			pml.writeCoefficientsToFile(retFileHandle);
		}
	}
	if (retFileHandle != 0)
	{
		closefile(retFileHandle);
	}
	return ret;
}

int TimeTssBase::saveFieldToFile(char *filename, FIELD_EMTYPE fieldToSave)
{
	int ret = ERR_OK;
	FILE *fp = NULL;
	ret = openfileWrite(filename, &fp);
	if (ret != ERR_OK || fp == NULL)
	{
		if (ret == ERR_OK)
		ret = ERR_FILE_OPEN_WRIT_EACCES;
	}
	else
	{
		size_t sizew;
		if (fieldToSave == Field_E)
		{
			sizew = fwrite(getRawMemoryE(), sizeof(Point3Dstruct), cellCount, fp);
		}
		else
		{
			sizew = fwrite(getRawMemoryH(), sizeof(Point3Dstruct), cellCount, fp);
		}
		fclose(fp);
		if (sizew != cellCount)
		{
			ret = ERR_FILE_WRITE_LESS;
		}
	}
	return ret;
}

int TimeTssBase::loadFieldFromFile(char *filename, FIELD_EMTYPE fieldToLoad)
{
	int ret = ERR_OK;
	size_t fSize = 0;
	Point3Dstruct *f = (Point3Dstruct *)ReadFileIntoMemory(filename, &fSize, &ret);
	if (ret == ERR_OK)
	{
		if (fieldMemorySize != fSize)
		{
			ret = ERR_FILESIZE_MISMATCH;
		}
		else
		{
			Point3Dstruct *field;
			if (fieldToLoad == Field_E)
			{
				field = getRawMemoryE();
			}
			else
			{
				field = getRawMemoryH();
			}
			for (size_t w = 0; w < cellCount; w++)
			{
				field[w].x = f[w].x;
				field[w].y = f[w].y;
				field[w].z = f[w].z;
			}
		}
		FreeMemory(f);
	}
	return ret;
}


//
// $Id: filter.hpp 5313 2013-12-17 18:06:54Z chambm $
//
//
// Original author: Witold Wolski <wewolski@gmail.com>
//
// Copyright : ETH Zurich
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef FILTERUTILS_H
#define FILTERUTILS_H
#include <math.h>
#include <algorithm>
#include <vector>
#include <functional>
#include <numeric>
#include <limits>

#include <boost/iterator/reverse_iterator.hpp>
#include <boost/bind.hpp>
#include <boost/math/distributions/normal.hpp>
#include <boost/cstdint.hpp>

#include "pwiz/utility/findmf/base/filter/utilities/preparedata.hpp"

namespace ralab
{
  namespace base
  {
    namespace filter
    {

      typedef boost::uint32_t uint32_t;
      template <typename TIterator, typename TFilterIterator, typename TOutputIterator>
      void filter_sequence(
          TIterator  dataBeg,   //!<[in] a univariate time series.
          TIterator  dataEnd,
          TFilterIterator filterBeg, //!<[in] a vector of filter coefficients in reverse time order (as for AR or MA coefficients). Lenght of filter must be odd.
          size_t fsize,
          TOutputIterator resBeg, //!<[out] result
          bool circular = false, //!<[in]  If TRUE, wrap the filter around the ends of the series, otherwise assume external values are missing (NA).
          uint32_t sides = 2  //!<[in] currently only sides 2 supported....
          )
      {
        typedef typename std::iterator_traits<TOutputIterator>::value_type TReal;
        if((fsize-1) % 2)
          {
            throw std::logic_error("filter size must be odd");
          }
        if(!circular)
          {
            //result.assign(data.size(), std::numeric_limits<TReal>::quiet_NaN() );

            size_t offset = static_cast<size_t>(fsize/2);
            for(std::size_t i = 0 ; i< offset; ++i, ++resBeg)
              {
                *resBeg = std::numeric_limits<TReal>::quiet_NaN();
              }

            for( ; dataBeg != dataEnd - (fsize -1) ; ++dataBeg, ++resBeg )
              {
                *resBeg = (std::inner_product(dataBeg , dataBeg + fsize, filterBeg ,0. ));
              }
          }
        else
          {

            std::vector<typename std::iterator_traits<TIterator>::value_type> tmp;
            typename std::vector<typename std::iterator_traits<TIterator>::value_type>::iterator it;
            it = utilities::prepareData( dataBeg, dataEnd, fsize , tmp );

            TIterator tbegin = tmp.begin();
            TIterator tend = it;

            for( ; tbegin != tend - (fsize-1 ) ; ++tbegin, ++resBeg )
              {
                *resBeg = std::inner_product(tbegin , tbegin + fsize, filterBeg ,0. );
              }
          }
      }// filter end

      /*! \brief Applies linear convolution (filtering) to a univariate time series

            The convolution filter is  \f$ y[i] = f[1]*x[i+o] + ... + f[p]*x[i+o-(p-1)] \f$
            where o is the offset: see sides for how it is determined.

            \param sides for convolution filters only.
                        If sides=1 the filter coefficients are for past values only;
                        if sides=2 they are centred around lag 0.
                        In this case the length of the filter should be odd,
                        but if it is even, more of the filter is forward in time than backward

            */
      template <typename TContainer>
      void filter(
          const TContainer & data,   //!<[in] a univariate time series.
          const TContainer & filter, //!<[in] a vector of filter coefficients in reverse time order (as for AR or MA coefficients). Lenght of filter must be odd.
          TContainer & result, //!<[out] result
          bool circular = false, //!<[in]  If TRUE, wrap the filter around the ends of the series, otherwise assume external values are missing (NA).
          uint32_t sides = 2  //!<[in] currently only sides 2 supported....
          )
      {
        result.resize(data.size());
        filter_sequence
            (
              data.begin(),
              data.end(),
              filter.begin(),
              filter.size(),
              result.begin(),
              circular,
              sides
              );
      }// filter end
    }//filter
  }//base
}//ralab

#endif


#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>

/// edge properties
class cEdge
{
public:
    cEdge()
        : myCost(1)
    {
    }
    int myCost;
};

/// node properties
class cNode
{
public:
    cNode(const std::string &name)
        : myName(name)
    {
    }
    cNode()
        : myName("???")
    {
    }
    std::string myName;
};

/// declaration of boost graph configuration
using namespace boost;
typedef boost::adjacency_list<
    boost::listS,
    boost::vecS,
    boost::directedS,
    cNode,
    cEdge>
    graph_t;

/// declaration of structure holding link input data
struct sBiLink
{
    int src;
    int dst;
    int dir; // allowed orientations of robot on link
    int cost;
};

class cRobot
{
public:
    graph_t myGraph;
    std::vector<int> myPath;

    graph_t ConstructBoostGraph(
        const std::vector<sBiLink> &vForward,
        const std::vector<sBiLink> &vBack,
        const std::vector<int> &vTurn);

    /** Find path
 * @param[in] start starting node info
 * @param[in] goal index of node aiming for
 */
    void Path(
        sBiLink &start,
        int goal);

    std::string linksText();
    std::string pathText();

private:
    /** Find or add node by name
 * @return index of node found
 *
 * If node by same bname already exists, return its index
 * otherwise add a new node and return its index
 */
    int findoradd(const std::string &name);

    /** Find node by name
 * @return index of node found, -1 if not found
 *
 */
    int find(const std::string &name);

    /** Add costed link
     * @param[in] s mode index
     * @param[in] d node index
     * @param[in] cost
     */
    void addLink(
        int s, int d,
        int cost);
};

std::vector<std::string> ParseSpaceDelimited(
    const std::string &l)
{
    std::vector<std::string> token;
    std::stringstream sst(l);
    std::string a;
    while (getline(sst, a, ' '))
        token.push_back(a);

    token.erase(
        remove_if(
            token.begin(),
            token.end(),
            [](std::string t) {
                return (t.empty());
            }),
        token.end());

    return token;
}

/// read input
std::vector<sBiLink> read(
    const std::string &fname,
    std::vector<int> &vTurn,
    sBiLink &start,
    int &goal)
{
    std::ifstream inf(fname);
    if (!inf.is_open())
    {
        std::cout << "cannot open " << fname << "\n";
    }
    std::vector<sBiLink> vBiLink;
    vTurn.clear();
    std::string line;
    int src, dst, dir;
    while (std::getline(inf, line))
    {
        std::cout << line << "\n";
        auto token = ParseSpaceDelimited(line);
        if (!token.size())
            continue;
        switch (token[0][0])
        {
        case 'l':
            if (token.size() != 5)
            {
                std::cout << "bad link: " << line << "\n";
                exit(1);
            }
            sBiLink l;
            l.src = atoi(token[1].c_str());
            l.dst = atoi(token[2].c_str());
            l.dir = atoi(token[3].c_str());
            l.cost = atoi(token[4].c_str());
            vBiLink.push_back(l);
            break;

        case 's':
            if (token.size() != 3)
            {
                std::cout << "bad start: " << line << "\n";
                exit(1);
            }
            start.src = atoi(token[1].c_str());
            if (token[2] == "b")
                start.dir = 2;
            else
                start.dir = 1;
            break;

        case 'g':
            if (token.size() != 2)
            {
                std::cout << "bad goal: " << line << "\n";
                exit(1);
            }
            goal = atoi(token[1].c_str());
            break;

        case 't':
            if (token.size() != 5)
            {
                std::cout << "bad turning node: " << line << "\n";
                exit(1);
            }
            vTurn.push_back(atoi(token[1].c_str()));
            break;

        default:
            std::cout << "bad row: " << line << "\n";
            break;
        }
    }
    std::cout << vBiLink.size() << " bidirectional links input\n";
    ;
    return vBiLink;
}

/** Split links according to allowed direction of travel
 * @param[in] vBiLink the input links
 * @param[out] vForward links allowing forward travel
 * @param[out] vBack links allowing backward travel
 * @param[out] vTurn modes where robot can turn around
 */
void split(
    const std::vector<sBiLink> &vBiLink,
    std::vector<sBiLink> &vForward,
    std::vector<sBiLink> &vBack,
    std::vector<int> &vTurn)
{

    for (auto &l : vBiLink)
    {
        switch (l.dir)
        {
        case 0:
            vForward.push_back(l);
            vBack.push_back(l);
            break;

        case 1:
            vForward.push_back(l);
            break;

        case 2:
            vBack.push_back(l);
            break;
        }
    }

    std::cout << "\nForward links\n";
    for (auto &l : vForward)
    {
        std::cout
            << std::to_string(l.src)
            << "f - "
            << std::to_string(l.dst)
            << "f\n";
    }
    std::cout << "\nBack links\n";
    for (auto &l : vBack)
    {
        std::cout
            << std::to_string(l.src)
            << "b - "
            << std::to_string(l.dst)
            << "b\n";
    }
    std::cout << "\nTurning Links\n";
    for (auto &n : vTurn)
    {
        std::cout
            << std::to_string(n)
            << "f - "
            << std::to_string(n)
            << "b\n";
    }
}

/** Find node by name
 * @return index of node found
 *
 * If node by same bname already exists, return its index
 * otherwise add a new node and return its index
 */
int cRobot::findoradd(const std::string &name)
{
    int n = find(name);
    if (n < 0)
        n = add_vertex(name, myGraph);
    return n;
}

int cRobot::find(const std::string &name)
{
    for (int n = 0; n < num_vertices(myGraph); n++)
    {
        if (myGraph[n].myName == name)
        {
            return n;
        }
    }
    return -1;
}

/// Create boost graph from combination of forward, backward and turning links
graph_t cRobot::ConstructBoostGraph(
    const std::vector<sBiLink> &vForward,
    const std::vector<sBiLink> &vBack,
    const std::vector<int> &vTurn)
{
    for (auto &l : vForward)
    {
        auto s = findoradd(std::to_string(l.src) + "f");
        auto d = findoradd(std::to_string(l.dst) + "f");
        addLink(s, d, l.cost);
    }
    for (auto &l : vBack)
    {
        auto s = findoradd(std::to_string(l.src) + "b");
        auto d = findoradd(std::to_string(l.dst) + "b");
        addLink(s, d, l.cost);
    }
    for (int n : vTurn)
    {
        // add edge begining and ending on node
        // which allows the robot to turn around
        // at zero cost
        auto s = findoradd(std::to_string(n) + "f");
        auto d = findoradd(std::to_string(n) + "b");
        addLink(s, d, 0);
    }

    return myGraph;
}

void cRobot::addLink(
    int s, int d,
    int cost)
{
    graph_t::edge_descriptor e = add_edge(s, d, myGraph).first;
    myGraph[e].myCost = cost;
    e = add_edge(d, s, myGraph).first;
    myGraph[e].myCost = cost;
}

std::string cRobot::linksText()
{
    std::stringstream ss;
    //     for (int n = 0; n < num_vertices(myGraph); n++)
    // {
    //     std::cout << myGraph[n].myName << " ";
    // }
    // ss << "\n";

    graph_traits<graph_t>::edge_iterator ei, ei_end;
    for (tie(ei, ei_end) = edges(myGraph); ei != ei_end; ++ei)
    {
        ss << "("
           << myGraph[source(*ei, myGraph)].myName << ","
           << myGraph[target(*ei, myGraph)].myName << ","
           << myGraph[*ei].myCost
           << ") ";
    }
    ss << "\n";
    return ss.str();
}

/** Find path
 * @param[in] G the graph
 * @param[in] start starting node info
 * @param[in] goal index of node aiming for
 */
void cRobot::Path(
    sBiLink &start,
    int goal)
{
    // starting node in boost graph
    std::string startNodeName = std::to_string(start.src);
    if (start.dir == 1)
        startNodeName += "f";
    else
        startNodeName += "b";
    int startNode = find(startNodeName);
    if (startNode < 0)
    {
        std::cout << "start " << startNodeName << " " << startNode << "\n";
        throw std::runtime_error("Bad path start");
    }

    // goal nodes in boost graph
    std::string sgf = std::to_string(goal) + "f";
    std::string sgb = std::to_string(goal) + "b";
    int goalf = find(sgf);
    int goalb = find(sgb);
    if (goalf < 0 && goalb < 0)
        throw std::runtime_error("Bad path goal");

    // run dijkstra algorithm
    std::vector<int> p(num_vertices(myGraph));
    std::vector<int> vDist(num_vertices(myGraph));
    boost::dijkstra_shortest_paths(
        myGraph,
        startNode,
        weight_map(get(&cEdge::myCost, myGraph))
            .predecessor_map(boost::make_iterator_property_map(
                p.begin(), get(boost::vertex_index, myGraph)))
            .distance_map(boost::make_iterator_property_map(
                vDist.begin(), get(boost::vertex_index, myGraph))));

    // choose closest possible goal
    int goalnode = goalf;
    if (goalf < 0 || goalb < 0)
    {
        if (goalf < 0)
            goalnode = goalb;
    }
    else
    {
        if (vDist[goalb] < vDist[goalf])
            goalnode = goalb;
    }

    // pick out path, starting at goal and finishing at start
    myPath.push_back(goalnode);
    int prev = goalnode;
    while (1)
    {
        //std::cout << prev << " " << p[prev] << ", ";
        int next = p[prev];
        myPath.push_back(next);
        if (next == startNode)
            break;
        prev = next;
    }

    // reverse so path goes from start to goal
    std::reverse(myPath.begin(), myPath.end());
}

std::string cRobot::pathText()
{
    std::stringstream ss;
    for (auto n : myPath)
        ss << myGraph[n].myName << " -> ";
    ss << "\n";
    return ss.str();
}

main(int argc, char *argv[])
{
    std::cout << "unirobot\n";

    // check command line
    if (argc != 2)
    {
        std::cout << "usage: unirobot <inputfilename>\n";
        exit(0);
    }

    cRobot Robot;

    // read input file
    sBiLink start;
    int goal;
    std::vector<int> vTurn;
    auto vBiLink = read(
        argv[1],
        vTurn,
        start,
        goal);

    // split graph
    std::vector<sBiLink> vForward;
    std::vector<sBiLink> vBack;
    split(
        vBiLink,
        vForward,
        vBack,
        vTurn);

    // construct boost graph
    auto G = Robot.ConstructBoostGraph(
        vForward,
        vBack,
        vTurn);

    std::cout << "\nCombined graph links\n"
              << Robot.linksText();

    // find path from start to goal
    Robot.Path(
        start,
        goal);

    // display path found
    std::cout << "\nPath: "
              << Robot.pathText();
}


/*
    Copyright (C) 2008 Wei Dong <wdong@princeton.edu>. All Rights Reserved.

    This file is part of LSHKIT.

    LSHKIT is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    LSHKIT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with LSHKIT.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * \file scan.cpp
 * \brief Linear scan dataset and construct benchmark.
 *
 * This program randomly picks Q points from a dataset as queries, and
 * then linear-scan the database to find K-NN/R-NN for each query to produce
 * a benchmark file.  For each query, the query point itself is excluded
 * from the K-NN/R-NN list.
 *
 * You can specify both K and R and the prorgram will search for the K
 * points closest to queries which are within distance range of R.
 * If K = 0, then all points within distance range of R are returned.
 * The default value of R is the maximal value of float.
 *
\verbatim
Allowed options:
  -h [ --help ]          produce help message.
  -Q [ -- ] arg (=1)     number of queries to sample.
  -K [ -- ] arg (=1)     number of nearest neighbors.
  --metric arg (=2)      1: L1; 2: L2
  -D [ --data ] arg      dataset path
  -B [ --benchmark ] arg output benchmark file path
\endverbatim
 *
 */
const char *help = "This program searches for K-NNs by linear scan and generate a benchmark file.";

#include <boost/program_options.hpp>
#include <boost/progress.hpp>
#include <boost/format.hpp>
#include <boost/timer.hpp>
#include <lshkit.h>

using namespace std;
using namespace lshkit;
namespace po = boost::program_options;

int main (int argc, char *argv[])
{
    string data_file;
    string query_file;

    unsigned K, Q, metric, seed;
    float R;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message.")
        (",Q", po::value<unsigned>(&Q)->default_value(1), "number of queries to sample.")
        (",K", po::value<unsigned>(&K)->default_value(0), "number of nearest neighbors.")
        (",R", po::value<float>(&R)->default_value(numeric_limits<float>::max()), "distance range to search for")
        ("seed", po::value<unsigned>(&seed)->default_value(0), "random number seed, 0 to use default.")
        ("metric", po::value<unsigned>(&metric)->default_value(2), "1: L1; 2: L2")
        ("data,D", po::value<string>(&data_file), "dataset path")
        ("benchmark,B", po::value<string>(&query_file), "output benchmark file path")
        ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    if (vm.count("help") || (vm.count("data") < 1) || (vm.count("benchmark") < 1))
    {
        cout << help << endl;
        cout << desc;
        return 0;
    }

    Matrix<float> data(data_file);

    Benchmark<unsigned> bench;
    bench.init(Q, data.getSize(), seed);
    boost::timer timer;

    timer.restart();
    if (metric == 1) {

        metric::l1<float> l1(data.getDim());

        boost::progress_display progress(Q);
        for (unsigned i = 0; i < Q; ++i)
        {
            unsigned q = bench.getQuery(i);
            Topk<unsigned> &topk = bench.getAnswer(i);
            topk.reset(K, R);
            for (unsigned j = 0; j < data.getSize(); ++j)
            {
                if (q == j) continue;
                topk << Topk<unsigned>::Element(j, l1(data[q],
                                        data[j]));
            }
            ++progress;
        }
    }
    else if (metric == 2) {

        metric::l2<float> l2(data.getDim());

        boost::progress_display progress(Q);
        for (unsigned i = 0; i < Q; ++i)
        {
            unsigned q = bench.getQuery(i);
            Topk<unsigned> &topk = bench.getAnswer(i);
            topk.reset(K, R);
            for (unsigned j = 0; j < data.getSize(); ++j)
            {
                if (q == j) continue;
                topk << Topk<unsigned>::Element(j, l2(data[q],
                                        data[j]));
            }
            ++progress;
        }
    }
    else {
        cout << "METRIC NOT SUPPORTED." << endl;
    }

    cout << boost::format("QUERY TIME: %1%s.") % timer.elapsed() << endl;
    bench.save(query_file);

    //timer.tuck("QUERY");

    return 0;
}


//  Copyright (c) 2011 David Bellot
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

#include <boost/numeric/ublas/fwd.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_expression.hpp>
#include <boost/numeric/ublas/operation/size.hpp>
#include <boost/numeric/ublas/tags.hpp>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/vector_expression.hpp>
#include <iostream>
#include "utils.hpp"

BOOST_UBLAS_TEST_DEF( test_vector_container )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Vector Container" );

    typedef double value_type;
    typedef boost::numeric::ublas::vector<value_type> vector_type;

    vector_type v(5);

    v(0) = 0.555950;
    v(1) = 0.108929;
    v(2) = 0.948014;
    v(3) = 0.023787;
    v(4) = 1.023787;

    // size(v)
    BOOST_UBLAS_DEBUG_TRACE( "size(v) = " << boost::numeric::ublas::size(v) << " ==> " << v.size() );
    BOOST_UBLAS_TEST_CHECK( boost::numeric::ublas::size(v) == v.size() );

    // size<1>(v)
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(v) = " << (boost::numeric::ublas::size<1>(v)) << " ==> " << v.size() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(v) == v.size()) );

    // [NOT_COMPILE]: this should *correctly* cause a compilation error
    // size<2>(v)
    //BOOST_UBLAS_DEBUG_TRACE( "size<2>(v) = " << (boost::numeric::ublas::size<vector_type,2>(v)) << " ==> " << v.size() );
    //BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<2>(v) == v.size()) );
    // [/NOT_COMPILE]
}

BOOST_UBLAS_TEST_DEF( test_vector_expression )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Vector Expression" );

    typedef double value_type;
    typedef boost::numeric::ublas::vector<value_type> vector_type;

    vector_type v(5);

    v(0) = 0.555950;
    v(1) = 0.108929;
    v(2) = 0.948014;
    v(3) = 0.023787;
    v(4) = 1.023787;

    // size(-v)
    BOOST_UBLAS_DEBUG_TRACE( "size(-v) = " << boost::numeric::ublas::size(-v) << " ==> " << (-v).size() );
    BOOST_UBLAS_TEST_CHECK( boost::numeric::ublas::size(-v) == (-v).size() );

    // size<1>(-v)
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(-v) = " << (boost::numeric::ublas::size<1>(-v)) << " ==> " << (-v).size() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(-v) == (-v).size()) );
}

BOOST_UBLAS_TEST_DEF( test_vector_reference )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Vector Reference" );

    typedef double value_type;
    typedef boost::numeric::ublas::vector<value_type> vector_type;
    typedef boost::numeric::ublas::vector_reference<vector_type> vector_reference_type;

    vector_type v(5);

    v(0) = 0.555950;
    v(1) = 0.108929;
    v(2) = 0.948014;
    v(3) = 0.023787;
    v(4) = 1.023787;

    // size(reference(v)
    BOOST_UBLAS_DEBUG_TRACE( "size(reference(v)) = " << boost::numeric::ublas::size(vector_reference_type(v)) << " ==> " << vector_reference_type(v).size() );
    BOOST_UBLAS_TEST_CHECK( boost::numeric::ublas::size(vector_reference_type(v)) == vector_reference_type(v).size() );

    // size<1>(reference(v))
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(reference(v)) = " << (boost::numeric::ublas::size<1>(vector_reference_type(v))) << " ==> " << vector_reference_type(v).size() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(vector_reference_type(v)) == vector_reference_type(v).size()) );
}

BOOST_UBLAS_TEST_DEF( test_row_major_matrix_container )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Row-major Matrix Container" );

    typedef double value_type;
    typedef boost::numeric::ublas::matrix<value_type, boost::numeric::ublas::row_major> matrix_type;

    matrix_type A(5,4);

    A(0,0) = 0.555950; A(0,1) = 0.274690; A(0,2) = 0.540605; A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.830123; A(1,2) = 0.891726; A(1,3) = 0.895283;
    A(2,0) = 0.948014; A(2,1) = 0.973234; A(2,2) = 0.216504; A(2,3) = 0.883152;
    A(3,0) = 0.023787; A(3,1) = 0.675382; A(3,2) = 0.231751; A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.675382; A(4,2) = 1.231751; A(4,3) = 1.450332;

    // [NOT_COMPILE]
    // size(A)
    //BOOST_UBLAS_DEBUG_TRACE( "size(A) = " << boost::numeric::ublas::size(A) << " ==> " << A.size1() );
    //BOOST_UBLAS_TEST_CHECK( boost::numeric::ublas::size(A) == A.size1() );
    // [/NOT_COMPILE]

    // size<1>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(A) = " << (boost::numeric::ublas::size<1>(A)) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(A) == A.size1()) );

    // size<2>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<2>(A) = " << (boost::numeric::ublas::size<2>(A)) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<2>(A) == A.size2()) );

    // size<major>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<major>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(A)) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(A) == A.size1()) );

    // size<minor>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<minor>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(A)) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(A) == A.size2()) );

    // size<leading>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<leading>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(A)) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(A) == A.size2()) );
}

BOOST_UBLAS_TEST_DEF( test_col_major_matrix_container )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Column-major Matrix Container" );

    typedef double value_type;
    typedef boost::numeric::ublas::matrix<value_type, boost::numeric::ublas::column_major> matrix_type;

    matrix_type A(5,4);

    A(0,0) = 0.555950; A(0,1) = 0.274690; A(0,2) = 0.540605; A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.830123; A(1,2) = 0.891726; A(1,3) = 0.895283;
    A(2,0) = 0.948014; A(2,1) = 0.973234; A(2,2) = 0.216504; A(2,3) = 0.883152;
    A(3,0) = 0.023787; A(3,1) = 0.675382; A(3,2) = 0.231751; A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.675382; A(4,2) = 1.231751; A(4,3) = 1.450332;

    // size<1>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(A) = " << (boost::numeric::ublas::size<1>(A)) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(A) == A.size1()) );

    // size<2>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<2>(A) = " << (boost::numeric::ublas::size<2>(A)) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<2>(A) == A.size2()) );

    // size<major>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<major>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(A)) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(A) == A.size2()) );

    // size<minor>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<minor>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(A)) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(A) == A.size1()) );

    // size<leading>(A)
    BOOST_UBLAS_DEBUG_TRACE( "size<leading>(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(A)) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(A) == A.size1()) );
}

BOOST_UBLAS_TEST_DEF( test_matrix_expression )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Matrix Expression" );

    typedef double value_type;
    typedef boost::numeric::ublas::matrix<value_type> matrix_type;

    matrix_type A(5,4);

    A(0,0) = 0.555950; A(0,1) = 0.274690; A(0,2) = 0.540605; A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.830123; A(1,2) = 0.891726; A(1,3) = 0.895283;
    A(2,0) = 0.948014; A(2,1) = 0.973234; A(2,2) = 0.216504; A(2,3) = 0.883152;
    A(3,0) = 0.023787; A(3,1) = 0.675382; A(3,2) = 0.231751; A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.675382; A(4,2) = 1.231751; A(4,3) = 1.450332;

    // size<1>(A')
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(A') = " << (boost::numeric::ublas::size<1>(boost::numeric::ublas::trans(A))) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(boost::numeric::ublas::trans(A)) == A.size2()) );

    // size<2>(A')
    BOOST_UBLAS_DEBUG_TRACE( "size<2>(A') = " << (boost::numeric::ublas::size<2>(boost::numeric::ublas::trans(A))) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<2>(boost::numeric::ublas::trans(A)) == A.size1()) );

    // size<major>(A') [A is row-major => A' column-major, and viceversa]
    BOOST_UBLAS_DEBUG_TRACE( "size<major>(A') = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(boost::numeric::ublas::trans(A))) << " ==> " << A.size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(boost::numeric::ublas::trans(A)) == A.size1()) );

    // size<minor>(A')  [A is row-major => A' column-major, and viceversa]
    BOOST_UBLAS_DEBUG_TRACE( "size<minor>(A') = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(boost::numeric::ublas::trans(A))) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(boost::numeric::ublas::trans(A)) == A.size2()) );

    // size<leading>(A')  [A row-major => A' column-major, and viceversa]
    BOOST_UBLAS_DEBUG_TRACE( "size<leading>(A') = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(boost::numeric::ublas::trans(A))) << " ==> " << A.size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(boost::numeric::ublas::trans(A)) == A.size2()) );
}

BOOST_UBLAS_TEST_DEF( test_matrix_reference )
{
    BOOST_UBLAS_DEBUG_TRACE( "TEST Matrix Reference" );

    typedef double value_type;
    typedef boost::numeric::ublas::matrix<value_type> matrix_type;
    typedef boost::numeric::ublas::matrix_reference<matrix_type> matrix_reference_type;

    matrix_type A(5,4);

    A(0,0) = 0.555950; A(0,1) = 0.274690; A(0,2) = 0.540605; A(0,3) = 0.798938;
    A(1,0) = 0.108929; A(1,1) = 0.830123; A(1,2) = 0.891726; A(1,3) = 0.895283;
    A(2,0) = 0.948014; A(2,1) = 0.973234; A(2,2) = 0.216504; A(2,3) = 0.883152;
    A(3,0) = 0.023787; A(3,1) = 0.675382; A(3,2) = 0.231751; A(3,3) = 0.450332;
    A(4,0) = 1.023787; A(4,1) = 1.675382; A(4,2) = 1.231751; A(4,3) = 1.450332;

    // size<1>(reference(A))
    BOOST_UBLAS_DEBUG_TRACE( "size<1>(reference(A)) = " << (boost::numeric::ublas::size<1>(matrix_reference_type(A))) << " ==> " << matrix_reference_type(A).size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<1>(matrix_reference_type(A)) == matrix_reference_type(A).size1()) );

    // size<2>(reference(A))
    BOOST_UBLAS_DEBUG_TRACE( "size<2>(reference(A)) = " << (boost::numeric::ublas::size<2>(matrix_reference_type(A))) << " ==> " << matrix_reference_type(A).size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<2>(matrix_reference_type(A)) == matrix_reference_type(A).size2()) );

    // size<major>(reference(A))
    BOOST_UBLAS_DEBUG_TRACE( "size<major>(reference(A) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(matrix_reference_type(A))) << " ==> " << matrix_reference_type(A).size1() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::major>(matrix_reference_type(A)) == matrix_reference_type(A).size1()) );

    // size<minor>(reference(A))
    BOOST_UBLAS_DEBUG_TRACE( "size<minor>(reference(A)) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(matrix_reference_type(A))) << " ==> " << matrix_reference_type(A).size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::minor>(matrix_reference_type(A)) == matrix_reference_type(A).size2()) );

    // size<leading>(reference(A))
    BOOST_UBLAS_DEBUG_TRACE( "size<leading>(reference(A)) = " << (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(matrix_reference_type(A))) << " ==> " << matrix_reference_type(A).size2() );
    BOOST_UBLAS_TEST_CHECK( (boost::numeric::ublas::size<boost::numeric::ublas::tag::leading>(matrix_reference_type(A)) == matrix_reference_type(A).size2()) );
}

int main()
{
    BOOST_UBLAS_TEST_BEGIN();

    BOOST_UBLAS_TEST_DO( test_vector_container );
    BOOST_UBLAS_TEST_DO( test_vector_expression );
    BOOST_UBLAS_TEST_DO( test_vector_reference );
    BOOST_UBLAS_TEST_DO( test_row_major_matrix_container );
    BOOST_UBLAS_TEST_DO( test_col_major_matrix_container );
    BOOST_UBLAS_TEST_DO( test_matrix_expression );
    BOOST_UBLAS_TEST_DO( test_matrix_reference );

    BOOST_UBLAS_TEST_END();
}


//==================================================================================================
/*!
  @file

  Copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/pack.hpp>
#include <boost/simd/function/clamp.hpp>
#include <boost/simd/constant/nan.hpp>
#include <boost/simd/meta/cardinal_of.hpp>
#include <simd_test.hpp>

template <typename T, int N, typename Env>
void test(Env& runtime)
{
  namespace bs = boost::simd;
  using p_t = bs::pack<T, N>;

  T a1[N],  b[N];
  for(int i = 0; i < N; ++i)
  {
     a1[i] = i;
     b[i]  = bs::clamp(a1[i], T(0.2*N), T(0.7*N));
   }
  p_t aa1(&a1[0], &a1[0]+N);
  p_t aa2(0.2*N);
  p_t aa3(0.7*N);
  p_t bb (&b [0], &b [0]+N);

  STF_IEEE_EQUAL(bs::clamp(aa1, aa2, aa3), bb);
}

STF_CASE_TPL("Check clamp on pack" , STF_NUMERIC_TYPES)
{
  namespace bs = boost::simd;
  using p_t = bs::pack<T>;
  static const std::size_t N = bs::cardinal_of<p_t>::value;
  test<T, N>(runtime);
  test<T, N/2>(runtime);
  test<T, N*2>(runtime);
}

STF_CASE_TPL("Check pedantic clamp on pack nan" , STF_IEEE_TYPES)
{
  namespace bs = boost::simd;
  using p_t = bs::pack<T>;
  auto nan =  bs::Nan<p_t>();
  STF_IEEE_EQUAL(bs::pedantic_(bs::clamp)(nan,p_t(2),p_t(4)) , nan);
}


#include <boost/numeric/ublas/triangular.hpp>


/*
 * Copyright (c) 2011, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <ecto/ecto.hpp>
#include <ecto/registry.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

using ecto::tendrils;
namespace ecto_test
{
  namespace pt = boost::posix_time;

  struct Metrics
  {
    ecto::spore<pt::ptime> in;
    ecto::spore<double> hz, latency_seconds;
    ecto::spore<unsigned> queue_size;
    std::deque<pt::ptime> times;

    static void declare_params(tendrils& parameters)
    {
      parameters.declare<unsigned>("queue_size", "size of window to collect statistics over", 10);
    }

    static void declare_io(const ecto::tendrils& parameters, ecto::tendrils& inputs, ecto::tendrils& outputs)
    {
      inputs.declare<pt::ptime> ("in", "input");
      outputs.declare<double>("hz");
      outputs.declare<double>("latency_seconds");
    }

    void configure(const tendrils& parameters, const tendrils& inputs, const tendrils& outputs)
    {
      queue_size = parameters["queue_size"];
      hz = outputs["hz"];
      latency_seconds = outputs["latency_seconds"];
      in = inputs["in"];
    }

    int process(const ecto::tendrils& inputs, const ecto::tendrils& outputs)
    {
      pt::ptime now(pt::microsec_clock::universal_time());
      times.push_back(now);
      if (times.size() > *queue_size)
        times.pop_front();

      *latency_seconds = (now - *in).total_microseconds() / 1e+6;
      std::cout << "Got message which is " << (now - *in) << " old.\n";
      pt::time_duration queuedur = now - times.front();
      double thishz = (1e+6 / queuedur.total_microseconds()) * (times.size()-1);
      *hz = thishz;
      std::cout << "hz=" << thishz << "\n";

      return 0;
    }
  };
}

ECTO_CELL(ecto_test, ecto_test::Metrics, "Metrics",
            "Calcluate bandwidth and latency based on timestamps received from an upstream ping.");


#ifndef SHASTA_DOMINATOR_TREE_HPP
#define SHASTA_DOMINATOR_TREE_HPP

/*******************************************************************************

This provides a bug fix for the 3-argument version of
boost::lengauer_tarjan_dominator_tree.
The fixed version is in the shasta namespace.

The bug fix is as follows.

The original version contains

    std::vector<VerticesSizeType> dfnum(numOfVertices, 0);

The fixed version below has instead

    std::vector<VerticesSizeType> dfnum(numOfVertices, std::numeric_limits<VerticesSizeType>::max());

As a result of the bug, the original version produces incorrect results
if the graph contains vertices that are unreachable from the entrance.

lengauer_tarjan_dominator_tree_without_dfs, which is eventually called,
includes the following comment about initializing dfnum/dfnumMap:

   * @pre Unreachable nodes must be masked as
   *      (std::numeric_limits<VerticesSizeType>::max)() in dfnumMap.

The above fix implements this requirement.
The fixed version below works correctly even if the graph contains unreachable vertices.

*******************************************************************************/

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dominator_tree.hpp>

namespace shasta {

    template<class Graph, class DomTreePredMap>
    void lengauer_tarjan_dominator_tree(const Graph &g,
        const typename boost::graph_traits<Graph>::vertex_descriptor &entry,
        DomTreePredMap domTreePredMap)
    {
        using namespace boost;

        // typedefs
        typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
        typedef typename graph_traits<Graph>::vertices_size_type VerticesSizeType;
        typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap;
        typedef iterator_property_map<
            typename std::vector<VerticesSizeType>::iterator, IndexMap> TimeMap;
        typedef iterator_property_map<typename std::vector<Vertex>::iterator,
            IndexMap> PredMap;

        // Make property maps
        const VerticesSizeType numOfVertices = num_vertices(g);
        if (numOfVertices == 0)
            return;

        const IndexMap indexMap = get(vertex_index, g);

        // ********* THE BUG FIX IS HERE **********************
        // The original versionwas filling the vector with 0.
        std::vector<VerticesSizeType> dfnum(numOfVertices,
            std::numeric_limits < VerticesSizeType > ::max());

        TimeMap dfnumMap(make_iterator_property_map(dfnum.begin(), indexMap));

        std::vector<Vertex> parent(numOfVertices,
            graph_traits < Graph > ::null_vertex());
        PredMap parentMap(make_iterator_property_map(parent.begin(), indexMap));

        std::vector<Vertex> verticesByDFNum(parent);

        // Run main algorithm
        boost::lengauer_tarjan_dominator_tree(g, entry, indexMap, dfnumMap,
            parentMap, verticesByDFNum, domTreePredMap);
    }

}

#endif


#pragma once

#include <vector>
#include <armadillo>
#include "../renderable.hpp"

enum MeshRenderable_HorizontalAnchor {MR_HA_CENTRE, MR_HA_LEFT, MR_HA_RIGHT};
enum MeshRenderable_VerticalAnchor {MR_VA_CENTRE, MR_VA_TOP, MR_VA_BOTTOM};

class MeshRenderable : public Renderable {
public:
    explicit MeshRenderable(json j);
    explicit MeshRenderable(const std::vector<arma::vec2> &points);

    void draw() const override;

    void set_alignment(MeshRenderable_HorizontalAnchor ha, MeshRenderable_VerticalAnchor va);

    json serialise() override;

protected:
    MeshRenderable();

    std::vector<arma::vec2> _points;
    arma::vec2 _anchor;

private:
    void draw_border() const;
    void draw_main() const;

    friend class AnimatedMeshRenderable;
};

class RectangleMeshRenderable : public MeshRenderable {
public:
    RectangleMeshRenderable(double w, double h);
};

class FilletedRectangleMeshRenderable : public MeshRenderable {
public:
    FilletedRectangleMeshRenderable(double w, double h, double r);
};

class RegularPolygonMeshRenderable : public MeshRenderable {
public:
    explicit RegularPolygonMeshRenderable(int n, double theta=M_PI_2);
};

class CircleMeshRenderable : public MeshRenderable {
public:
    explicit CircleMeshRenderable(double radius=0.5);
};


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_CONSTANT_CONSTANTS_VALMIN_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_CONSTANTS_VALMIN_HPP_INCLUDED

#include <boost/simd/include/functor.hpp>
#include <boost/simd/meta/int_c.hpp>
#include <boost/simd/meta/float.hpp>
#include <boost/simd/meta/double.hpp>
#include <boost/simd/constant/hierarchy.hpp>

#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4146)
#endif

namespace boost { namespace simd
{
  namespace tag
  {
   /*!
     @brief Valmin generic tag

     Represents the Valmin constant in generic contexts.

     @par Models:
        Hierarchy
   **/
    struct Valmin : ext::pure_constant_<Valmin>
    {
      typedef double default_type;
      typedef ext::pure_constant_<Valmin> parent;

    /// INTERNAL ONLY
      template<class Target, class Dummy=void>
      struct  apply
            : meta::int_c < typename Target::type, 0> {};
      template<class... Args>
      static BOOST_FORCEINLINE BOOST_AUTO_DECLTYPE dispatch(Args&&... args)
      BOOST_AUTO_DECLTYPE_BODY( dispatching_Valmin( ext::adl_helper(), static_cast<Args&&>(args)... ) )
    };

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::single_<T>,Dummy>
          : meta::single_<0xFF7FFFFFUL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::double_<T>,Dummy>
          : meta::double_<0xFFEFFFFFFFFFFFFFULL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::int8_<T>,Dummy>
          : meta::int_c<T, T(-128)> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::int16_<T>,Dummy>
          : meta::int_c<T, T(-32768)> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::int32_<T>,Dummy>
    : meta::int_c < T
                  , T(-boost::simd::uint32_t(2147483648UL))
                  > {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Valmin::apply<boost::dispatch::meta::int64_<T>,Dummy>
      : meta::int_c < T
                    , T(-boost::simd::uint64_t(9223372036854775808ULL))
                    > {};
  }
  namespace ext
  {
   template<class Site>
   BOOST_FORCEINLINE generic_dispatcher<tag::Valmin, Site> dispatching_Valmin(adl_helper, boost::dispatch::meta::unknown_<Site>, ...)
   {
     return generic_dispatcher<tag::Valmin, Site>();
   }
   template<class... Args>
   struct impl_Valmin;
  }
  /*!
    Generates the least finite value of a type.

    @par Semantic:

    @code
    T r = Valmin<T>();
    @endcode

    is similar to:

    @code
    if T is integral
      r = 1 << (sizeof(T)*8-1);
    else if T is double
      r = -1.7976931348623157e+308;
    else if T is float
      r = -3.4028234e+38f;
    @endcode

  **/
  BOOST_SIMD_CONSTANT_IMPLEMENTATION(boost::simd::tag::Valmin, Valmin)
} }

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif

#include <boost/simd/constant/common.hpp>

#endif


// Copyright (c) 2015-2017 Matthias Noack <ma.noack.pr@gmail.com>
//
// See accompanying file LICENSE and README for further information.

#ifndef noma_noma_num_types_hpp
#define noma_noma_num_types_hpp

#include <cstdint> // fixed width integers
#include <complex>

#include <boost/format.hpp>

namespace noma {
namespace num {

#ifdef NUM_TYPES_SINGLE_PRECISION
#warning "Using single precision (float)"
using real_t         = float;
using long_real_t    = double;
//	using real_vec_t     = float_v;
#else
using real_t         = double;
using long_real_t    = long double;
//	using real_vec_t     = double_v;
#endif

using bool_t         = std::uint8_t; // needed for OpenCL memory layout interoperability
using int_t          = std::int32_t;
using uint_t         = std::uint32_t;
using complex_t      = std::complex<real_t>;
using long_complex_t = std::complex<long_real_t>;

// number of digits to print to get the bit-wisely equal real_t when reading back the data
int_t get_real_to_text_digits();

/* boost format instance for printing numbers, to
 * a) have a consistent format, and
 * b) not loose precision
 * use as a copy (to loose constness), outside of loops (for performance), e.g.
 *
 * auto format = real_format;
 * for (...) out << format % my_number;
 */
extern const boost::format int_format;
extern const boost::format real_format;
extern const boost::format complex_format;
// default delimiter character used for output
extern const char default_delimiter;

} // namespace num
} // namespace noma

#endif // noma_noma_num_types_hpp


// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/SVD>
#include <Eigen/LU>

template<typename MatrixType> void svd(const MatrixType& m)
{
  /* this test covers the following files:
     SVD.h
  */
  typename MatrixType::Index rows = m.rows();
  typename MatrixType::Index cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  MatrixType a = MatrixType::Random(rows,cols);
  Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> b =
    Matrix<Scalar, MatrixType::RowsAtCompileTime, 1>::Random(rows,1);
  Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> x(cols,1), x2(cols,1);

  {
    SVD<MatrixType> svd(a);
    MatrixType sigma = MatrixType::Zero(rows,cols);
    MatrixType matU  = MatrixType::Zero(rows,rows);
    sigma.diagonal() = svd.singularValues();
    matU = svd.matrixU();
    VERIFY_IS_APPROX(a, matU * sigma * svd.matrixV().transpose());
  }

  if (rows==cols)
  {
    if (ei_is_same_type<RealScalar,float>::ret)
    {
      MatrixType a1 = MatrixType::Random(rows,cols);
      a += a * a.adjoint() + a1 * a1.adjoint();
    }
    SVD<MatrixType> svd(a);
    x = svd.solve(b);
    VERIFY_IS_APPROX(a * x,b);
  }

  if(rows==cols)
  {
    SVD<MatrixType> svd(a);
    MatrixType unitary, positive;
    svd.computeUnitaryPositive(&unitary, &positive);
    VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
    VERIFY_IS_APPROX(positive, positive.adjoint());
    for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
    VERIFY_IS_APPROX(unitary*positive, a);

    svd.computePositiveUnitary(&positive, &unitary);
    VERIFY_IS_APPROX(unitary * unitary.adjoint(), MatrixType::Identity(unitary.rows(),unitary.rows()));
    VERIFY_IS_APPROX(positive, positive.adjoint());
    for(int i = 0; i < rows; i++) VERIFY(positive.diagonal()[i] >= 0); // cheap necessary (not sufficient) condition for positivity
    VERIFY_IS_APPROX(positive*unitary, a);
  }
}

template<typename MatrixType> void svd_verify_assert()
{
  MatrixType tmp;

  SVD<MatrixType> svd;
  VERIFY_RAISES_ASSERT(svd.solve(tmp))
  VERIFY_RAISES_ASSERT(svd.matrixU())
  VERIFY_RAISES_ASSERT(svd.singularValues())
  VERIFY_RAISES_ASSERT(svd.matrixV())
  VERIFY_RAISES_ASSERT(svd.computeUnitaryPositive(&tmp,&tmp))
  VERIFY_RAISES_ASSERT(svd.computePositiveUnitary(&tmp,&tmp))
  VERIFY_RAISES_ASSERT(svd.computeRotationScaling(&tmp,&tmp))
  VERIFY_RAISES_ASSERT(svd.computeScalingRotation(&tmp,&tmp))
}

void test_svd()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( svd(Matrix3f()) );
    CALL_SUBTEST_2( svd(Matrix4d()) );
    CALL_SUBTEST_3( svd(MatrixXf(7,7)) );
    CALL_SUBTEST_4( svd(MatrixXd(14,7)) );
    // complex are not implemented yet
//     CALL_SUBTEST(svd(MatrixXcd(6,6)) );
//     CALL_SUBTEST(svd(MatrixXcf(3,3)) );
  }

  CALL_SUBTEST_1( svd_verify_assert<Matrix3f>() );
  CALL_SUBTEST_2( svd_verify_assert<Matrix4d>() );
  CALL_SUBTEST_3( svd_verify_assert<MatrixXf>() );
  CALL_SUBTEST_4( svd_verify_assert<MatrixXd>() );

  // Test problem size constructors
  CALL_SUBTEST_9( SVD<MatrixXf>(10, 20) );
}


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Copyright (c) 2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO

#include <geometry_test_common.hpp>

#include <boost/geometry/algorithms/assign.hpp>

#include <boost/geometry/strategies/cartesian/intersection.hpp>
#include <boost/geometry/strategies/intersection_result.hpp>

#include <boost/geometry/policies/relate/intersection_points.hpp>
#include <boost/geometry/policies/relate/direction.hpp>
#include <boost/geometry/policies/relate/tupled.hpp>

#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp>

#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/segment.hpp>

template <typename IntersectionPoints>
static int check(IntersectionPoints const& is,
                std::size_t index, double expected_x, double expected_y)
{
    if (expected_x != -99 && expected_y != -99 && is.count > index)
    {
        double x = bg::get<0>(is.intersections[index]);
        double y = bg::get<1>(is.intersections[index]);

        BOOST_CHECK_CLOSE(x, expected_x, 0.001);
        BOOST_CHECK_CLOSE(y, expected_y, 0.001);
        return 1;
    }
    return 0;
}

template <typename P>
static void test_segment_intersection(std::string const& case_id,
                int x1, int y1, int x2, int y2,
                int x3, int y3, int x4, int y4,
                char expected_how, bool expected_opposite,
                int expected_arrival1, int expected_arrival2,
                int expected_x1, int expected_y1,
                int expected_x2 = -99, int expected_y2 = -99)

{
    boost::ignore_unused(case_id);

    typedef bg::model::referring_segment<const P> segment_type;

    P p1, p2, p3, p4;
    bg::assign_values(p1, x1, y1);
    bg::assign_values(p2, x2, y2);
    bg::assign_values(p3, x3, y3);
    bg::assign_values(p4, x4, y4);

    segment_type s12(p1, p2);
    segment_type s34(p3, p4);

    bg::detail::segment_as_subrange<segment_type> sr12(s12);
    bg::detail::segment_as_subrange<segment_type> sr34(s34);

    typedef bg::segment_intersection_points<P> result_type;

    typedef bg::policies::relate::segments_intersection_points
        <
            result_type
        > points_policy_type;

    // Get the intersection point (or two points)
    result_type is
        = bg::strategy::intersection::cartesian_segments<>
            ::apply(sr12, sr34, points_policy_type());

    // Get just a character for Left/Right/intersects/etc, purpose is more for debugging
    bg::policies::relate::direction_type dir
        = bg::strategy::intersection::cartesian_segments<>
            ::apply(sr12, sr34, bg::policies::relate::segments_direction());

    std::size_t expected_count =
        check(is, 0, expected_x1, expected_y1)
        + check(is, 1, expected_x2, expected_y2);

    BOOST_CHECK_EQUAL(is.count, expected_count);
    BOOST_CHECK_EQUAL(dir.how, expected_how);
    BOOST_CHECK_EQUAL(dir.opposite, expected_opposite);
    BOOST_CHECK_EQUAL(dir.arrival[0], expected_arrival1);
    BOOST_CHECK_EQUAL(dir.arrival[1], expected_arrival2);
}

template <typename P, typename Pair>
static void test_segment_ratio(std::string const& case_id,
                int x1, int y1, int x2, int y2,
                int x3, int y3, int x4, int y4,
                Pair expected_pair_a1, Pair expected_pair_a2,
                Pair expected_pair_b1, Pair expected_pair_b2,
                int exp_ax1, int exp_ay1, int exp_ax2, int exp_ay2,
                std::size_t expected_count = 2)

{
    boost::ignore_unused(case_id);

    typedef bg::model::referring_segment<const P> segment_type;

    P p1, p2, p3, p4;
    bg::assign_values(p1, x1, y1);
    bg::assign_values(p2, x2, y2);
    bg::assign_values(p3, x3, y3);
    bg::assign_values(p4, x4, y4);

    segment_type s12(p1, p2);
    segment_type s34(p3, p4);

    bg::detail::segment_as_subrange<segment_type> sr12(s12);
    bg::detail::segment_as_subrange<segment_type> sr34(s34);

    typedef bg::segment_intersection_points<P> result_type;

    typedef bg::policies::relate::segments_intersection_points
        <
            result_type
        > points_policy_type;

    // Get the intersection point (or two points)
    result_type is
        = bg::strategy::intersection::cartesian_segments<>
            ::apply(sr12, sr34, points_policy_type());

    typedef bg::segment_ratio<typename bg::coordinate_type<P>::type> ratio_type;

    ratio_type expected_a1(expected_pair_a1.first, expected_pair_a1.second);
    ratio_type expected_a2(expected_pair_a2.first, expected_pair_a2.second);
    ratio_type expected_b1(expected_pair_b1.first, expected_pair_b1.second);
    ratio_type expected_b2(expected_pair_b2.first, expected_pair_b2.second);

    BOOST_CHECK_EQUAL(is.count, expected_count);

    BOOST_CHECK_EQUAL(is.fractions[0].robust_ra, expected_a1);
    BOOST_CHECK_EQUAL(is.fractions[0].robust_rb, expected_b1);
    BOOST_CHECK_EQUAL(bg::get<0>(is.intersections[0]), exp_ax1);
    BOOST_CHECK_EQUAL(bg::get<1>(is.intersections[0]), exp_ay1);

    if (expected_count == 2)
    {
        BOOST_CHECK_EQUAL(bg::get<0>(is.intersections[1]), exp_ax2);
        BOOST_CHECK_EQUAL(bg::get<1>(is.intersections[1]), exp_ay2);
        BOOST_CHECK_EQUAL(is.fractions[1].robust_ra, expected_a2);
        BOOST_CHECK_EQUAL(is.fractions[1].robust_rb, expected_b2);
    }
}

template <typename P>
void test_all()
{
    // Collinear - non opposite

    //       a1---------->a2
    // b1--->b2
    test_segment_intersection<P>("n1",
        2, 0, 6, 0,
        0, 0, 2, 0,
        'a', false, -1, 0,
        2, 0);

    //       a1---------->a2
    //    b1--->b2
    test_segment_intersection<P>("n2",
        2, 0, 6, 0,
        1, 0, 3, 0,
        'c', false, -1, 1,
        2, 0, 3, 0);

    //       a1---------->a2
    //       b1--->b2
    test_segment_intersection<P>("n3",
        2, 0, 6, 0,
        2, 0, 4, 0,
        'c', false, -1, 1,
        2, 0, 4, 0);

    //       a1---------->a2
    //          b1--->b2
    test_segment_intersection<P>("n4",
        2, 0, 6, 0,
        3, 0, 5, 0,
        'c', false, -1, 1,
        3, 0, 5, 0);

    //       a1---------->a2
    //              b1--->b2
    test_segment_intersection<P>("n5",
        2, 0, 6, 0,
        4, 0, 6, 0,
        'c', false, 0, 0,
        4, 0, 6, 0);

    //       a1---------->a2
    //                 b1--->b2
    test_segment_intersection<P>("n6",
        2, 0, 6, 0,
        5, 0, 7, 0,
        'c', false, 1, -1,
        5, 0, 6, 0);

    //       a1---------->a2
    //                    b1--->b2
    test_segment_intersection<P>("n7",
        2, 0, 6, 0,
        6, 0, 8, 0,
        'a', false, 0, -1,
        6, 0);

    // Collinear - opposite
    //       a1---------->a2
    // b2<---b1
    test_segment_intersection<P>("o1",
        2, 0, 6, 0,
        2, 0, 0, 0,
        'f', true, -1, -1,
        2, 0);

    //       a1---------->a2
    //    b2<---b1
    test_segment_intersection<P>("o2",
        2, 0, 6, 0,
        3, 0, 1, 0,
        'c', true, -1, -1,
        2, 0, 3, 0);

    //       a1---------->a2
    //       b2<---b1
    test_segment_intersection<P>("o3",
        2, 0, 6, 0,
        4, 0, 2, 0,
        'c', true, -1, 0,
        2, 0, 4, 0);

    //       a1---------->a2
    //           b2<---b1
    test_segment_intersection<P>("o4",
        2, 0, 6, 0,
        5, 0, 3, 0,
        'c', true, -1, 1,
        3, 0, 5, 0);

    //       a1---------->a2
    //              b2<---b1
    test_segment_intersection<P>("o5",
        2, 0, 6, 0,
        6, 0, 4, 0,
        'c', true, 0, 1,
        4, 0, 6, 0);

    //       a1---------->a2
    //                b2<---b1
    test_segment_intersection<P>("o6",
        2, 0, 6, 0,
        7, 0, 5, 0,
        'c', true, 1, 1,
        5, 0, 6, 0);

    //       a1---------->a2
    //                    b2<---b1
    test_segment_intersection<P>("o7",
        2, 0, 6, 0,
        8, 0, 6, 0,
        't', true, 0, 0,
        6, 0);

    //   a1---------->a2
    //   b1---------->b2
    test_segment_intersection<P>("e1",
        2, 0, 6, 0,
        2, 0, 6, 0,
        'e', false, 0, 0,
        2, 0, 6, 0);

    //   a1---------->a2
    //   b2<----------b1
    test_segment_intersection<P>("e1",
        2, 0, 6, 0,
        6, 0, 2, 0,
        'e', true, 0, 0,
        2, 0, 6, 0);

    // Disjoint (in vertical direction, picture still horizontal)
    //   a2<---a1
    //                      b2<---b1
    test_segment_intersection<P>("case_recursive_boxes_1",
        10, 7, 10, 6,
        10, 10, 10, 9,
        'd', false, 0, 0,
        -1, -1, -1, -1);

}

template <typename P>
void test_ratios()
{
    // B inside A
    //       a1------------>a2
    //          b1--->b2
    test_segment_ratio<P>("n4",
        2, 0, 7, 0,
        3, 0, 5, 0,
        std::make_pair(1, 5), std::make_pair(3, 5), // IP located on 1/5, 3/5 w.r.t A
        std::make_pair(0, 1), std::make_pair(1, 1), // IP located on 0, 1 w.r.t. B
        // IP's are ordered as in A (currently)
        3, 0, 5, 0);

    //       a1------------>a2
    //           b2<---b1
    test_segment_ratio<P>("o4",
        2, 0, 7, 0,
        5, 0, 3, 0,
        std::make_pair(1, 5), std::make_pair(3, 5),
        std::make_pair(1, 1), std::make_pair(0, 1),
        3, 0, 5, 0);

    //       a2<------------a1
    //           b2<---b1
    test_segment_ratio<P>("o4b",
        7, 0, 2, 0,
        5, 0, 3, 0,
        std::make_pair(2, 5), std::make_pair(4, 5),
        std::make_pair(0, 1), std::make_pair(1, 1),
        5, 0, 3, 0);

    //       a2<------------a1
    //          b1--->b2
    test_segment_ratio<P>("o4c",
        7, 0, 2, 0,
        3, 0, 5, 0,
        std::make_pair(2, 5), std::make_pair(4, 5),
        std::make_pair(1, 1), std::make_pair(0, 1),
        5, 0, 3, 0);

    // Touch-interior
    //       a1---------->a2
    //       b1--->b2
    test_segment_ratio<P>("n3",
        2, 0, 7, 0,
        2, 0, 4, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(0, 1), std::make_pair(1, 1),
        2, 0, 4, 0);

    //    a2<-------------a1
    //             b2<----b1
    test_segment_ratio<P>("n3b",
        7, 0, 2, 0,
        7, 0, 5, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(0, 1), std::make_pair(1, 1),
        7, 0, 5, 0);

    // A inside B
    //          a1--->a2
    //       b1------------>b2
    test_segment_ratio<P>("rn4",
        3, 0, 5, 0,
        2, 0, 7, 0,
        std::make_pair(0, 1), std::make_pair(1, 1),
        std::make_pair(1, 5), std::make_pair(3, 5),
        3, 0, 5, 0);

    //           a2<---a1
    //       b1------------>b2
    test_segment_ratio<P>("ro4",
        5, 0, 3, 0,
        2, 0, 7, 0,
        std::make_pair(0, 1), std::make_pair(1, 1),
        std::make_pair(3, 5), std::make_pair(1, 5),
        5, 0, 3, 0);

    //           a2<---a1
    //       b2<------------b1
    test_segment_ratio<P>("ro4b",
        5, 0, 3, 0,
        7, 0, 2, 0,
        std::make_pair(0, 1), std::make_pair(1, 1),
        std::make_pair(2, 5), std::make_pair(4, 5),
        5, 0, 3, 0);

    //          a1--->a2
    //       b2<------------b1
    test_segment_ratio<P>("ro4c",
        3, 0, 5, 0,
        7, 0, 2, 0,
        std::make_pair(0, 1), std::make_pair(1, 1),
        std::make_pair(4, 5), std::make_pair(2, 5),
        3, 0, 5, 0);

    // B inside A, boundaries intersect
    // We change the coordinates a bit (w.r.t. n3 above) to have it asymmetrical
    //       a1---------->a2
    //       b1--->b2
    test_segment_ratio<P>("n3",
        2, 0, 7, 0,
        2, 0, 4, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(0, 1), std::make_pair(1, 1),
        2, 0, 4, 0);

    //       a1---------->a2
    //       b2<---b1
    test_segment_ratio<P>("o3",
        2, 0, 7, 0,
        4, 0, 2, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(1, 1), std::make_pair(0, 1),
        2, 0, 4, 0);

    //       a1---------->a2
    //              b1--->b2
    test_segment_ratio<P>("n5",
        2, 0, 7, 0,
        5, 0, 7, 0,
        std::make_pair(3, 5), std::make_pair(1, 1),
        std::make_pair(0, 1), std::make_pair(1, 1),
        5, 0, 7, 0);

    //       a1---------->a2
    //              b2<---b1
    test_segment_ratio<P>("o5",
        2, 0, 7, 0,
        7, 0, 5, 0,
        std::make_pair(3, 5), std::make_pair(1, 1),
        std::make_pair(1, 1), std::make_pair(0, 1),
        5, 0, 7, 0);

    // Generic (overlaps)
    //       a1---------->a2
    //    b1----->b2
    test_segment_ratio<P>("n2",
        2, 0, 7, 0,
        1, 0, 4, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(1, 3), std::make_pair(1, 1),
        2, 0, 4, 0);

    // Same, b reversed
    test_segment_ratio<P>("n2_b",
        2, 0, 7, 0,
        4, 0, 1, 0,
        std::make_pair(0, 1), std::make_pair(2, 5),
        std::make_pair(2, 3), std::make_pair(0, 1),
        2, 0, 4, 0);

    // Same, both reversed
    test_segment_ratio<P>("n2_c",
        7, 0, 2, 0,
        4, 0, 1, 0,
        std::make_pair(3, 5), std::make_pair(1, 1),
        std::make_pair(0, 1), std::make_pair(2, 3),
        4, 0, 2, 0);

    //       a1---------->a2
    //                 b1----->b2
    test_segment_ratio<P>("n6",
        2, 0, 6, 0,
        5, 0, 8, 0,
        std::make_pair(3, 4), std::make_pair(1, 1),
        std::make_pair(0, 1), std::make_pair(1, 3),
        5, 0, 6, 0);

    // Degenerated one
    //       a1---------->a2
    //             b1/b2
    const int ignored = 99;
    test_segment_ratio<P>("degenerated1",
        2, 0, 6, 0,
        5, 0, 5, 0,
        std::make_pair(3, 4), // IP located on 3/4 w.r.t A
        std::make_pair(ignored, 1), // not checked
        std::make_pair(0, 1), // IP located at any place w.r.t B, so 0
        std::make_pair(ignored, 1), // not checked
        5, 0,
        ignored, ignored,
        1);

    test_segment_ratio<P>("degenerated2",
        5, 0, 5, 0,
        2, 0, 6, 0,
        std::make_pair(0, 1), std::make_pair(ignored, 1),
        std::make_pair(3, 4), std::make_pair(ignored, 1),
        5, 0,
        ignored, ignored,
        1);

    // Vertical one like in box_poly5 but in integer
    test_segment_ratio<P>("box_poly5",
        45, 25, 45, 15,
        45, 22, 45, 19,
        std::make_pair(3, 10), std::make_pair(6, 10),
        std::make_pair(0, 1), std::make_pair(1, 1),
        45, 22, 45, 19);
}

int test_main(int, char* [])
{
    // We don't rescale but use integer points as, by nature, robust points
    test_all<bg::model::point<int, 2, bg::cs::cartesian> >();
    test_ratios<bg::model::point<int, 2, bg::cs::cartesian> >();
    return 0;
}


#pragma once

#include <polyfem/ProblemWithSolution.hpp>

#include <vector>
#include <Eigen/Dense>

namespace polyfem
{
	class TestProblem: public ProblemWithSolution
	{
	public:
		TestProblem(const std::string &name);

		VectorNd eval_fun(const VectorNd &pt) const override { return eval_impl(pt); }
		AutodiffGradPt eval_fun(const AutodiffGradPt &pt) const override { return eval_impl(pt); }
		AutodiffHessianPt eval_fun(const AutodiffHessianPt &pt) const override { return eval_impl(pt); }

		bool is_scalar() const override { return params_["is_scalar"]; }

		void set_parameters(const json &params) override;

	private:
		template <typename T> T eval_impl(const T &pt) const;

	private:
		json params_;
	};
}


#include "test_data.hpp"
#include "../src/shared_operations.hpp"
#include "logging.h"
#include <boost/test/unit_test.hpp>
#include "libs/ml_models/logistic_regression.h"
#include <opencv/cxcore.h>
#include <iostream>
//#define TEST_CODE_FOR_MODEL_LOG_REG
#ifdef TEST_CODE_FOR_MODEL_LOG_REG
#include <map>

using forward_m = std::map<int, int>;

bool set_label_map(const cv::Mat &_labels_i, forward_m& fm);
cv::Mat remap_labels(const cv::Mat& _labels_i, const forward_m& lmap);

void simulate(cv::Mat _labels_i)
{
    //std::cout<<"the type of the matrix that we are working with is "<<_labels_i<<std::endl;
    forward_m forward_mapper;
    /*for (auto i = 0; i < _labels_i.rows; ++i) {
        float t = _labels_i.at<float>(i, 0);
        std::cout<< " ["<<i<<"] = "<<t;
    }
    std::cout<<std::endl;*/
#if 0
        auto ii = t + 0.123f;
        //std::cout<<"t "<<t<<", ii "<<ii<<", ";
        _labels_i.at<float>(i, 0) = ii;
    }
    std::cout<<std::endl;
#endif
    set_label_map(_labels_i, forward_mapper);
    cv::Mat labels_l = remap_labels(_labels_i, forward_mapper);
    int num_classes = (int) forward_mapper.size();
    if(num_classes < 2)
    {
        std::cerr<<"number of classes must be at least 2\n";
    } else {
        std::cout<<"number of classes is "<<num_classes<<std::endl;
    }
}

cv::Mat remap_labels(const cv::Mat& _labels_i, const forward_m& lmap)
{
    cv::Mat labels;
    _labels_i.convertTo(labels, CV_32S);

    cv::Mat new_labels = cv::Mat::zeros(labels.rows, labels.cols, labels.type());

    for(int i =0;i<labels.rows;i++) {
        new_labels.at<int>(i,0) = lmap.find(labels.at<int>(i,0))->second;
    }
    return new_labels;
}

bool set_label_map(const cv::Mat &_labels_i, forward_m& forward_mapper)
{
    // this function creates two maps to map user defined labels to program friendly labels two ways.
    int ii = 0;
    cv::Mat labels;

    auto labels_o = cv::Mat(0,1, CV_8U);
    auto labels_n = cv::Mat(0,1, CV_8U);

    _labels_i.convertTo(labels, CV_32S);

    for(int i = 0;i<labels.rows;i++)
    {
        forward_mapper[labels.at<int>(i)] += 1;
        //std::cout<<"setting "<<labels.at<int>(i)<<" to "<<forward_mapper[labels.at<int>(i)]<<" from "<<_labels_i.at<float>(i, 0)<<"\n";
    }

    for(auto it = forward_mapper.begin(); it != forward_mapper.end(); ++it)
    {
        forward_mapper[it->first] = ii;
        labels_o.push_back(it->first);
        labels_n.push_back(ii);
        ii += 1;
    }
    return true;
}
#endif  // TEST_CODE_FOR_MODEL_LOG_REG
BOOST_AUTO_TEST_CASE(empty_data_set_test_lr)
{
    mlmodels::regression_LR_model model;
    auto m = model.train(mlmodels::training_data{},
            mlmodels::class_data{},
            mlmodels::logistic_regression::args{}
        );
    BOOST_TEST((m.get() == nullptr), "the model that we should get back from empty data set should be empty as well");
    mlmodels::testing_result out;
    auto r = model.predict(m, mlmodels::testing_data{}, out);
    BOOST_TEST(r == false, "should failed because training did not run");
    BOOST_TEST(out.empty(), "there should not be any data from the test");
}

BOOST_AUTO_TEST_CASE(test_model_create_lr)
{
    const auto& samples = ut_data::unittest_data();
    const auto& classes = ut_data::classes4ut();
    BOOST_TEST_REQUIRE(mlmodels::rows(samples) == classes.size());
#ifdef TEST_CODE_FOR_MODEL_LOG_REG
        simulate(mlmodels::detail::prepare_labels(classes, CV_32F));
#else
    try {
        mlmodels::regression_LR_model lg;
        auto m = lg.train(samples,
                classes,
                mlmodels::logistic_regression::args{}
        );
        BOOST_TEST_REQUIRE((m.get() != nullptr), "we are expecting that this train would succeed");
        const auto& test_samples = ut_data::samples4test();
        BOOST_TEST_REQUIRE(mlmodels::rows(test_samples) < mlmodels::rows(samples));
        BOOST_TEST_REQUIRE(mlmodels::columns(test_samples) == mlmodels::columns(samples));
        auto p = lg.test(m, test_samples, ut_data::NUMBER_OF_CLASSES);
        BOOST_TEST_REQUIRE(!p.empty(), "we are expecting to get entries from the test");
        BOOST_TEST_REQUIRE(p.size() == mlmodels::rows(test_samples));
    //mlmodels::save_model(m);
#ifdef PRINT_MODEL_RESULTS
        for (auto f : p) {
            std::cout<<"["<<f<<"]";
        }
        std::cout<<std::endl;
#endif
    } catch (const std::exception& e) {
        BOOST_TEST(false, "we do not except an exception but we've got "<<e.what());
    } catch (...) {
        BOOST_TEST(false, "unknown exception while running unit test");
    }
#endif  // TEST_CODE_FOR_MODEL_LOG_REG
}


// cppray.cpp : Defines the entry point for the application.
//

#include "cppray.h"
#include <boost/lambda/lambda.hpp>

void RenderFrame(const shared_ptr<RayTraceRenderData> &renderData,
                 const shared_ptr<Scene> &scene, const string &outputFilePath)
{
  {
    LogTimer renderResult("total render time: ");
    SceneRenderer sceneRenderer;
    auto pixelArray = sceneRenderer.RenderScene(renderData, scene);
    pixelArray->SaveAsPng(outputFilePath);
  }
}

void RenderAnimation(const shared_ptr<RayTraceRenderData> &renderData,
                     const shared_ptr<Scene> &scene,
                     const string &outputContentRoot)
{
  int numFrames = 60;
  double cameraRadius = 15.0;
  double theta = 0; // boost::math::constants::pi<double>() / 2.0; // xy plane
  double tickAngleDegrees = 360 / numFrames;

  for (int i = 1; i <= numFrames; i++)
  {
    // todo: path.combine to check for full path, ensure path separators, etc.
    stringstream outputFilePathStream;
    outputFilePathStream << outputContentRoot << "cppray" << i << ".png";
    string outputFilePath = outputFilePathStream.str();
    // string outputFilePath = outputContentRoot + "cppray.png";

    /*
You can simply rotate your setup: let ϕ∈[0,2π] parametrize your circle like you
did, but use θ∈[0,π2] to describe the rotation of your plane. Then you can use

x=rcosϕcosθ
y=rsinϕ
z=rcosϕsinθ

For θ=0 this gives a circle in the xy plane, and for θ=π/2 the circle lies in
the zy plane.    */

    double currentAngleDegrees = tickAngleDegrees * (i - 1);
    double phi =
        currentAngleDegrees * boost::math::constants::pi<double>() / 180;
    double x = cameraRadius * cos(phi) * cos(theta);
    double y = cameraRadius * sin(phi);
    double z = -cameraRadius; // cameraRadius * cos(phi) * sin(theta);

    x = (double)i;
    y = (double)i;

    POS_VECTOR cameraPos = {x, y, z};

    cout << "x: " << x << "  y: " << y << "  z: " << z << endl;

    scene->GetCamera()->SetPosition(cameraPos);

    cout << "starting rendering..." << i << endl;
    RenderFrame(renderData, scene, outputFilePath);
  }
}

int main()
{
  string inputContentRoot = "../content/";
  string outputContentRoot = "/Users/mzuber/repos/cppray/output/";
  // directory.CreateDirectory(outputContentRoot);

  const int processorCount = 8;

  const int width = 400;
  const int height = 400;
  const int rayTraceDepth = 5;

  POS_VECTOR cameraPos = {60.0, 7.5, 150.0};
  POS_VECTOR cameraLookAt = {-0.1, 0.1, 0.0};
  POS_VECTOR cameraUp = {0.0, 0.0, 1.0};
  double cameraFov = 50.0;
  COLOR_VECTOR backgroundColor = {0.0, 0.0, 0.0};
  double backgroundAmbience = 0.2;

  double sphereRadius = 2.0;
  double sphereDistanceIncrement = 4.0;
  int numSpheresPerAxis = 10;

  bool showPlane = true;
  POS_VECTOR planePos = {1.0, 0.0, 0.0};
  double planeDVal = 0.0;

  auto renderData = make_shared<RayTraceRenderData>(
      width, height, rayTraceDepth, processorCount, inputContentRoot);
  // auto scene = SceneFactory::CreateMarblesScene();

  auto scene = SceneFactory::CreateMarblesSceneWithParameters(
      cameraPos, cameraLookAt, cameraUp, cameraFov, backgroundColor,
      backgroundAmbience, sphereRadius, sphereDistanceIncrement,
      numSpheresPerAxis, showPlane, planePos, planeDVal);

  bool animation = false;

  if (animation)
  {
    RenderAnimation(renderData, scene, outputContentRoot);
  }
  else
  {
    string outputFilePath = outputContentRoot + "cppray.png";
    RenderFrame(renderData, scene, outputFilePath);
  }

  return 0;
}