//
// This program is used to study how to calculate (SS|SS)^{m}
// for the recursive relation. Basically, it focus on the
// fmt function:
// f_{m}(t) = \int^{1}_{0} u^{2m} e^{-tu^{2}} du
// it needs the boost library to calcualte fmt
// fenglai liu
// Oct. 2013
//
// for reference, see Harris paper and the reference cited inside:
// Harris, Frank E
// Evaluation of GTO molecular integrals
// International Journal of Quantum Chemistry, 1983, Vol. 23, Page 1469--1478
//
// note:
// we found that the approximation of (2m-1)!!/R expression is
// not numerical stable. Combined with down recursive relation,
// it introduces greater error compared with other methods.
// Therefore we finally abadon it.
//
//
//

// common C head files used in the program
#include<cstdlib>
#include<cstdio>

// external math functions
#include<cmath>

// common C++ head files may be used in the program
#include<iostream>
#include<fstream>
#include<iomanip>
#include<string>
#include<vector>
#include<list>
#include<set>
#include<map>
#include<iterator>
#include<algorithm>

#include <boost/math/special_functions/binomial.hpp>  // special functions in math
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/timer.hpp>
using namespace boost::math;
using namespace boost;
using namespace std;
#define PI              3.1415926535897932384626E0

double fm(const double& a, const int& m);
double doubleFac(const int& m, const int& n);

double fm(const double& a, const int& m) {
	double x = 1.0E0;
	if (fabs(a)<1.0E-14) return (pow(x,2*m+1)/(2*m+1));
	double f12 = 1.0E0/2.0E0;
	double p   = 1.0E0/(2.0E0*pow(a,m+f12));
	double upperLimit = a*pow(x,2.0E0);
	return tgamma_lower(m+f12,upperLimit)*p;
}

double doubleFac(const int& m, const int& n) {
	// calculate (2m-1)!!/(2m+2n+1)!!
	double x = 1.0E0;
	for(int i=0; i<=n; i++) {
		x *= 1.0E0/(2*m+2*i+1);
	}
	return x;
}

int main()
{
	///////////////////////////////////////////////////
	// global settings
	// step length and number of claculation for
	// time performance
	// global error is the error range
	// if the difference is less than the error, we
	// think the error could be omitted
	///////////////////////////////////////////////////
	double steplength  = 0.000001;
	double globalError = 1.0E-14;
	int M_limmit       = 8;
	double T_max_limit = 40.0E0;
	double T_min_limit = 1.8E0;
	int numSteps       = (T_max_limit-T_min_limit)/steplength;
	double largest     = 0.0E0;

	/////////////////////////////////////////////////////////////////////
	// this section testing the up recursice relation for M_limit = 8  //
	/////////////////////////////////////////////////////////////////////
	cout << endl << endl;
	cout << "===========================================================" << endl;
	cout << "testing the up recursive relation for m = 1 to " << M_limmit << endl;
	cout << "error range is " << globalError << endl;
	cout << "step length for T is " << steplength << endl;
	cout << "T is ranging from " << T_min_limit << " to " <<T_max_limit << endl;
	cout << "===========================================================" << endl;
	for (int j = 0; j<numSteps; j++) {
		double T = T_min_limit+steplength*j;
		double sqT = sqrt(T);
		double fmt= erf(sqT)*sqrt(PI)/2.0E0;
		double et = exp(-T);
		double e0 = fmt/sqT;
		double oneO2T = 0.5E0/T;
		for(int i=1; i<=M_limmit; i++) {
			double s = fm(T,i);
			double e = oneO2T*((2*i-1)*e0-et);
			double d  = fabs(s-e);
			double d0 = s-e;
			if (d>globalError) {
				printf("m is  %d, T   is %-16.14f, difference is %-16.14f\n", i, T, d0);
				if (d>largest) largest = d;
			}
			e0 = e;
		}
	}
	printf("largest difference is %-16.14f\n", largest);

	/////////////////////////////////////////////////////////////////////
	// this section testing the up recursice relation for M_limit = 9  //
	/////////////////////////////////////////////////////////////////////
	cout << endl << endl;
	globalError = 1.0E-13;
	M_limmit    = 9;
	cout << "===========================================================" << endl;
	cout << "testing the up recursive relation for m = 1 to " << M_limmit << endl;
	cout << "error range is " << globalError << endl;
	cout << "step length for T is " << steplength << endl;
	cout << "T is ranging from " << T_min_limit << " to " <<T_max_limit << endl;
	cout << "===========================================================" << endl;
	largest = 0.0E0;
	for (int j = 0; j<numSteps; j++) {
		double T = T_min_limit+steplength*j;
		double sqT = sqrt(T);
		double fmt= erf(sqT)*sqrt(PI)/2.0E0;
		double et = exp(-T);
		double e0 = fmt/sqT;
		double oneO2T = 0.5E0/T;
		for(int i=1; i<=M_limmit; i++) {
			double s = fm(T,i);
			double e = oneO2T*((2*i-1)*e0-et);
			double d  = fabs(s-e);
			double d0 = s-e;
			if (d>globalError) {
				printf("m is  %d, T   is %-16.14f, difference is %-16.14f\n", i, T, d0);
				if (d>largest) largest = d;
			}
			e0 = e;
		}
	}
	printf("largest difference is %-16.14f\n", largest);

	/////////////////////////////////////////////////////////////////////
	// this section testing the up recursice relation for M_limit = 10 //
	/////////////////////////////////////////////////////////////////////
	cout << endl << endl;
	globalError = 1.0E-12;
	M_limmit    = 10;
	cout << "===========================================================" << endl;
	cout << "testing the up recursive relation for m = 1 to " << M_limmit << endl;
	cout << "error range is " << globalError << endl;
	cout << "step length for T is " << steplength << endl;
	cout << "T is ranging from " << T_min_limit << " to " <<T_max_limit << endl;
	cout << "===========================================================" << endl;
	largest = 0.0E0;
	for (int j = 0; j<numSteps; j++) {
		double T = T_min_limit+steplength*j;
		double sqT = sqrt(T);
		double fmt= erf(sqT)*sqrt(PI)/2.0E0;
		double et = exp(-T);
		double e0 = fmt/sqT;
		double oneO2T = 0.5E0/T;
		for(int i=1; i<=M_limmit; i++) {
			double s = fm(T,i);
			double e = oneO2T*((2*i-1)*e0-et);
			double d  = fabs(s-e);
			double d0 = s-e;
			if (d>globalError) {
				printf("m is  %d, T   is %-16.14f, difference is %-16.14f\n", i, T, d0);
				if (d>largest) largest = d;
			}
			e0 = e;
		}
	}
	printf("largest difference is %-16.14f\n", largest);

	return 0;
}


/* Simple program for solving the two-dimensional diffusion
   equation or Poisson equation using Jacobi's iterative method
   Note that this program does not contain a loop over the time
   dependence. It uses OpenMP to parallelize the spatial part.
*/

#include <iostream>
#include <iomanip>
#include <armadillo>
#include <omp.h>
using namespace std;
using namespace arma;

int JacobiSolver(int, double, double, mat &, mat &, double);

int main(int argc, char * argv[]){
  int Npoints = 100;
  double ExactSolution;
  double dx = 1.0/(Npoints-1);
  double dt = 0.25*dx*dx;
  double tolerance = 1.0e-8;
  mat A = zeros<mat>(Npoints,Npoints);
  mat q = zeros<mat>(Npoints,Npoints);

  int thread_num;
  omp_set_num_threads(4);
  thread_num = omp_get_max_threads ();
  cout << "  The number of processors available = " << omp_get_num_procs () << endl ;
  cout << "  The number of threads available    = " << thread_num <<  endl;
  // setting up an additional source term
  for(int i = 0; i < Npoints; i++)
    for(int j = 0; j < Npoints; j++)
      q(i,j) = -2.0*M_PI*M_PI*sin(M_PI*dx*i)*sin(M_PI*dx*j);

  int itcount = JacobiSolver(Npoints,dx,dt,A,q,tolerance);

  // Testing against exact solution
  double sum = 0.0;
  for(int i = 0; i < Npoints; i++){
    for(int j=0;j < Npoints; j++){
      ExactSolution = -sin(M_PI*dx*i)*sin(M_PI*dx*j);
      sum += fabs((A(i,j) - ExactSolution));
    }
  }
  cout << setprecision(5) << setiosflags(ios::scientific);
  cout << "Jacobi error is " << sum/Npoints << " in " << itcount << " iterations" << endl;
}

// Function for setting up the iterative Jacobi solver
int JacobiSolver(int N, double dx, double dt, mat &A, mat &q, double abstol)
{
  int MaxIterations = 100000;

  double D = dt/(dx*dx);
  // initial guess
  mat Aold = randu<mat>(N,N);
  // Boundary conditions, all zeros
  for(int i=0; i < N; i++){
    A(0,i) = 0.0;
    A(N-1,i) = 0.0;
    A(i,0) = 0.0;
    A(i,N-1) = 0.0;
  }
  double sum = 1.0;
  int k = 0;
  // Start the iterative solver
  while (k < MaxIterations && sum > abstol){
  int i, j;
  sum = 0.0;
  // Define parallel region
# pragma omp parallel default(shared) private (i, j) reduction(+:sum)
  {
     # pragma omp for
    for(i = 1; i < N-1; i++){
      for(j = 1; j < N-1; j++){
	A(i,j) = dt*q(i,j) + Aold(i,j) +
	  D*(Aold(i+1,j) + Aold(i,j+1) - 4.0*Aold(i,j) +
	     Aold(i-1,j) + Aold(i,j-1));
      }
    }
    for(i = 0; i < N;i++){
      for(j = 0; j < N;j++){
	sum += fabs(Aold(i,j)-A(i,j));
	Aold(i,j) = A(i,j);
      }
    }
    sum /= (N*N);
  } //end parallel region
  k++;
  } //end while loop
  return k;
}


// translated from DFT Python code as shown in
// https://www.youtube.com/watch?v=sX-DNi_SX-Q
//
// Compile:
// g++ -g --std=c++11 -o dft dft.cpp  -Ieigen
//
// Execute:
// ./dft  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//
// Plot using gnuplot:
// plot "plot_out.txt" using 1:2 with lines lw 3, "plot_in.txt" using 1:2:(0.03) with circles fill solid

#include <iostream>
#include <fstream>
#include <Eigen/Dense>
#include <complex>

using std::cout;
using namespace Eigen;
using std::pow;
using std::exp;
using std::ofstream;
using std::ostream;

typedef std::complex<double> complex_t;

complex_t omega( int n )
{
    double arg = 2. * M_PI / n;
    return complex_t( cos(arg), sin(arg));
}

MatrixXcd omegaMatrix( int n )
{
    complex_t om = omega(n);
    MatrixXcd m;
    m.resize( n, n);

    int j,k;
    for( j = 0; j < n; j++)
        for( k = 0; k < n; k++)
            m(j,k) = pow( om, -k * j );

    return m / n;
}

VectorXcd DFT( VectorXcd Y )
{
    int n = Y.size();
    int start = (int)ceil( ((double)n) / 2. ) - 1;
    complex_t oms = pow( omega(n), (double)start);

    for( int k = 0; k < n; k++)
        Y[k] *= pow( oms, (double)k);

    VectorXcd res;
    res = omegaMatrix( n ) * Y;

    for( int k = 0; k < res.size(); k++)
        res[k] *= pow( -1., k + start);

    return res;
}

void print_input( const VectorXcd &Y, ostream &os)
{
    int n = Y.size();

    for( int k = 0; k < n; k++)
        os << (-M_PI + 2. * k * M_PI / n) << "  " << Y[k].real() << "\n";
}

void print_DFTPoly( const VectorXcd &Y, double step_x, ostream &os)
{
    int n = Y.size();

    VectorXcd coeffs = DFT( Y );

    int zero = (n - 1) / 2;

    for( double x = -M_PI; x <= M_PI; x += step_x)
    {
        double S = coeffs[zero].real();
        for( int k = 1; k < (int)ceil( ((double)n) / 2.); k++)
        {
            S += cos(k * x) * (coeffs[zero-k] + coeffs[zero+k]).real();
            S += sin(k * x) * (coeffs[zero-k] - coeffs[zero+k]).imag();
        }

        if( n % 2 == 0 )
            S += cos(n * x / 2.) * coeffs[coeffs.size()-1].real();

        os << x << "  " << S << "\n";
    }
}

int main( int argc, char **argv)
{
    VectorXcd in;

    int n = argc - 1;

    if( n < 3 )
    {
        std::cerr << "input too small\n";
        return 1;
    }

    in.resize(n);

    for( int i = 0; i < n; i++)
        in(i) = atof( argv[i+1] );

    ofstream plot_in( "plot_in.txt" );
    ofstream plot_out( "plot_out.txt" );
    print_input( in, plot_in);
    print_DFTPoly( in, 0.01, plot_out);

    return 0;
}


#include "renderer_math_cpu.h"
#include <Eigen/Eigenvalues>
#include <algorithm>

Eigen::MatrixXd RendererMathCpu::createCompanionMatrix(
	const Eigen::VectorXd& coefficients)
{
	Eigen::Index N = coefficients.size() - 1;
	Eigen::MatrixXd m = Eigen::MatrixXd::Zero(N, N);

	//diagonal, 1 below diagonal
	for (Eigen::Index i = 0; i < N - 1; ++i)
		m(i + 1, i) = 1;

	//add coefficients in the first row
	//scaled by 1/c[0], the highest degree
	for (Eigen::Index i = 0; i < N; ++i)
		m(0, i) = -coefficients[i + 1] / coefficients[0];

	return m;
}

Eigen::VectorXcd RendererMathCpu::rootsFromCompanionMatrix(const Eigen::MatrixXd& m)
{
	Eigen::EigenSolver<Eigen::MatrixXd> es(m, false);
	Eigen::VectorXcd eigenvalues = es.eigenvalues();
	return eigenvalues;
}

std::vector<double> RendererMathCpu::extractRealRoots(const Eigen::VectorXcd& complexRoots, double epsilon)
{
	std::vector<double> realRoots;
	realRoots.reserve(complexRoots.size());
	for (Eigen::Index i=0; i<complexRoots.size(); ++i)
	{
		if (std::abs(complexRoots[i].imag()) < epsilon)
			realRoots.push_back(complexRoots[i].real());
	}
	std::sort(realRoots.begin(), realRoots.end());
	return realRoots;
}


// students_t_example3.cpp
// Copyright Paul A. Bristow 2006, 2007.

// Use, modification and distribution are 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)

// Example 3 of using Student's t.

// A general guide to Student's t is at
// http://en.wikipedia.org/wiki/Student's_t-test
// (and many other elementary and advanced statistics texts).
// It says:
// The t statistic was invented by William Sealy Gosset
// for cheaply monitoring the quality of beer brews.
// "Student" was his pen name.
// Gosset was statistician for Guinness brewery in Dublin, Ireland,
// hired due to Claude Guinness's innovative policy of recruiting the
// best graduates from Oxford and Cambridge for applying biochemistry
// and statistics to Guinness's industrial processes.
// Gosset published the t test in Biometrika in 1908,
// but was forced to use a pen name by his employer who regarded the fact
// that they were using statistics as a trade secret.
// In fact, Gosset's identity was unknown not only to fellow statisticians
// but to his employer - the company insisted on the pseudonym
// so that it could turn a blind eye to the breach of its rules.

// The Students't distribution function is described at
// http://en.wikipedia.org/wiki/Student%27s_t_distribution

#include <boost/math/distributions/students_t.hpp>
   using boost::math::students_t;  // Probability of students_t(df, t).

#include <iostream>
   using std::cout;    using std::endl;
#include <iomanip>
   using std::setprecision;    using std::setw;
#include <cmath>
   using std::sqrt;

// This example of a two-sided test is from:
// B. M. Smith & M. B. Griffiths, Analyst, 1982, 107, 253,
// from Statistics for Analytical Chemistry, 3rd ed. (1994), pp 58-59
// J. C. Miller and J. N. Miller, Ellis Horwood ISBN 0 13 0309907

// Concentrations of lead (ug/l) determined by two different methods
// for each of four test portions,
// the concentration of each portion is significantly different,
// the values may NOT be pooled.
// (Called a 'paired test' by Miller and Miller
// because each portion analysed has a different concentration.)

// Portion  Wet oxidation Direct Extraction
//   1           71            76
//   2           61            68
//   3           50            48
//   4           60            57

const int portions = 4;
const int methods = 2;
float data [portions][methods] = {{71, 76}, {61,68}, {50, 48}, {60, 57}};
float diffs[portions];

int main()
{
   cout << "Example3 using Student's t function. " << endl;
   float mean_diff = 0.f;
   cout << "\n""Portion  wet_oxidation  Direct_extraction  difference" << endl;
   for (int portion = 0; portion < portions; portion++)
   { // Echo data and differences.
      diffs[portion] = data[portion][0] - data[portion][1];
      mean_diff += diffs[portion];
      cout << setw(4) << portion << ' ' << setw(14) << data[portion][0] << ' ' << setw(18)<< data[portion][1] << ' ' << setw(9) << diffs[portion] << endl;
   }
   mean_diff /= portions;
   cout << "Mean difference = " << mean_diff << endl; // -1.75

   float sd_diffs = 0.f;
   for (int portion = 0; portion < portions; portion++)
   { // Calculate standard deviation of differences.
      sd_diffs +=(diffs[portion] - mean_diff) * (diffs[portion] - mean_diff);
   }
   int degrees_of_freedom = portions-1; // Use the n-1 formula.
   sd_diffs /= degrees_of_freedom;
   sd_diffs = sqrt(sd_diffs);
   cout << "Standard deviation of differences = " << sd_diffs << endl; // 4.99166
   // Standard deviation of differences = 4.99166
   double t = mean_diff * sqrt(static_cast<double>(portions))/ sd_diffs; // -0.70117
   cout << "Student's t = " << t << ", if " << degrees_of_freedom << " degrees of freedom." << endl;
   // Student's t = -0.70117, if 3 degrees of freedom.
   cout << "Probability of the means being different is "
    << 2.F * cdf(students_t(degrees_of_freedom), t) << "."<< endl; // 0.266846 * 2 = 0.533692
   // Double the probability because using a 'two-sided test' because
   // mean for 'Wet oxidation' could be either
   // greater OR LESS THAN for 'Direct extraction'.

   return 0;
}  // int main()

/*

Output is:

Example3 using Student's t function.
Portion  wet_oxidation  Direct_extraction  difference
   0             71                 76        -5
   1             61                 68        -7
   2             50                 48         2
   3             60                 57         3
Mean difference = -1.75
Standard deviation of differences = 4.99166
Student's t = -0.70117, if 3 degrees of freedom.
Probability of the means being different is 0.533692.

*/


#include <Core/Core.h>
#include <Eigen/Eigen.h>

using namespace Upp;

using namespace Eigen;

void NonLinearTests();
void FFTTests();

struct SerialTest {
	MatrixXd m;
	VectorXd v;
	SerialTest() : m(2, 2), v(3){}
	void Print() {
		Cout() << "\nHere is the matrix:\n" << m;
		Cout() << "\nHere is the vector:\n" << v;
	}
	void Serialize(Stream& stream) {
		::Serialize(stream, m);
		::Serialize(stream, v);
	}
	void Jsonize(JsonIO &jio) {
		jio("matrix", m)("vector", v);
	}
	void Xmlize(XmlIO &xml) {
		xml("matrix", m)("vector", v);
	}
};

CONSOLE_APP_MAIN
{
	StdLogSetup(LOG_COUT|LOG_FILE);

	UppLog() << "Eigen library demo";

	// https://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html
	UppLog() << "\n\nTutorial page 1 - The Matrix class";

	UppLog() << "\n\nCoefficient accessors";
	{
		MatrixXd m(2,2);
		m(0,0) = 3;
		m(1,0) = 2.5;
		m(0,1) = -1;
		m(1,1) = m(1,0) + m(0,1);
		UppLog() << "\nHere is the matrix m:\n" << m;

		VectorXd v(2);
		v(0) = 4;
		v(1) = v(0) - 1;
		UppLog() << "\nHere is the vector v:\n" << v;
	}
	UppLog() << "\n\nResizing";
	{
		MatrixXd m(2,5);
		m.resize(4,3);
		UppLog() << "\nThe matrix m is of size " << m.rows() << "x" << m.cols();
		UppLog() << "\nIt has " << m.size() << " coefficients";

		VectorXd v(2);
		v.resize(5);
		UppLog() << "\nThe vector v is of size " << v.size();
		UppLog() << "\nAs a matrix, v is of size " << v.rows() << "x" << v.cols();
	}
	UppLog() << "\n\nAssignment and resizing";
	{
		double _dat[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};// Assignment from C vector
		VectorXd dat = Map<VectorXd>(_dat, sizeof(_dat)/sizeof(double));
		UppLog() << "\nC array data is " << dat.transpose();

		const int dec = 5;
    	VectorXd decimated = Map<VectorXd, 0, InnerStride<dec>>(dat.data(), 1+((dat.size()-1)/dec));
    	UppLog() << "\nDecimated " << decimated.transpose();

		VectorXd even = Map<VectorXd, 0, InnerStride<2>>(dat.data(), (dat.size()+1)/2);
		UppLog() << "\nEven " << even.transpose();

		VectorXd odd = Map<VectorXd, 0, InnerStride<2>>(dat.data()+1, dat.size()/2);
		UppLog() << "\nOdd  " << odd.transpose();

		MatrixXf a(2,2);
		UppLog() << "\na is of size " << a.rows() << "x" << a.cols();
		MatrixXf b(3,3);
		a = b;
		UppLog() << "\na is now of size " << a.rows() << "x" << a.cols();
	}

	// https://eigen.tuxfamily.org/dox-devel/group__TutorialMatrixArithmetic.html
	UppLog() << "\n\nTutorial page 2 - Matrix and vector arithmetic";

	UppLog() << "\n\nAddition and subtraction";
	{
		Matrix2d a;
		a << 1, 2,
		     3, 4;
		MatrixXd b(2,2);
		b << 2, 3,
		     1, 4;

		UppLog() << "\na + b =\n" << a + b;
		UppLog() << "\na - b =\n" << a - b;
		UppLog() << "\nDoing a += b;";
		a += b;
		UppLog() << "\nNow a =\n" << a;

		Vector3d v(1,2,3);
		Vector3d w(1,0,0);
		UppLog() << "\n-v + w - v =\n" << -v + w - v;
	}
	UppLog() << "\n\nScalar multiplication and division";
	{
		Matrix2d a;
		a << 1, 2,
		     3, 4;
		Vector3d v(1,2,3);
		UppLog() << "\na * 2.5 =\n" << a * 2.5;
		UppLog() << "\n0.1 * v =\n" << 0.1 * v;
		UppLog() << "\nDoing v *= 2;";
		v *= 2;
		UppLog() << "\nNow v =\n" << v;
	}
	UppLog() << "\n\nTransposition and conjugation";
	{
		MatrixXcf a = MatrixXcf::Random(2,2);
		UppLog() << "\nHere is the matrix a\n" << a;
		UppLog() << "\nHere is the matrix a^T\n" << a.transpose();
		UppLog() << "\nHere is the conjugate of a\n" << a.conjugate();
		UppLog() << "\nHere is the matrix a^*\n" << a.adjoint();

		VectorXd v(5);
		v << 1, 2, 3, 4, 5;
		UppLog() << "\n\nInitial vector  " << v.transpose();
		UppLog() <<   "\nReversed vector " << v.reverse().transpose();
	}
	UppLog() << "\n\nMatrix-matrix and matrix-vector multiplication";
	{
		Matrix2d mat;
		mat << 1, 2,
		       3, 4;
		Vector2d u(-1,1), v(2,0);
		UppLog() << "\nHere is mat*mat:\n" << mat*mat;
		UppLog() << "\nHere is mat*u:\n" << mat*u;
		UppLog() << "\nHere is u^T*mat:\n" << u.transpose()*mat;
		UppLog() << "\nHere is u^T*v:\n" << u.transpose()*v;
		UppLog() << "\nHere is u*v^T:\n" << u*v.transpose();
		UppLog() << "\nLet's multiply mat by itself";
		mat *= mat;
		UppLog() << "\nNow mat is mat:\n" << mat;
	}
	UppLog() << "\n\nDot product and cross product";
	{
		Vector3d v(1,2,3);
	  	Vector3d w(0,1,2);

	  	UppLog() << "\nDot product: " << v.dot(w);
	  	double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
	  	UppLog() << "\nDot product via a matrix product: " << dp;
	  	UppLog() << "\nCross product:\n" << v.cross(w);
	}
	UppLog() << "\n\nBasic arithmetic reduction operations";
	{
		Eigen::Matrix2d mat;
		mat << 1, 2,
		       3, 4;
		UppLog() << "\nHere is mat.sum():       " << mat.sum();
		UppLog() << "\nHere is mat.prod():      " << mat.prod();
		UppLog() << "\nHere is mat.mean():      " << mat.mean();
		UppLog() << "\nHere is mat.minCoeff():  " << mat.minCoeff();
		UppLog() << "\nHere is mat.maxCoeff():  " << mat.maxCoeff();
		UppLog() << "\nHere is mat.trace():     " << mat.trace();

		Matrix3f m = Matrix3f::Random();
		ptrdiff_t i, j;
		float minOfM = m.minCoeff(&i, &j);
		UppLog() << "\nHere is the matrix m:\n" << m;
		UppLog() << "\nIts minimum coefficient (" << minOfM
		       << ") is at position (" << i << "," << j << ")\n";

		RowVector4i v = RowVector4i::Random();
		ptrdiff_t maxOfV = v.maxCoeff(&i);
		UppLog() << "\nHere is the vector v: " << v;
		UppLog() << "\nIts maximum coefficient (" << maxOfV
			   << ") is at position " << i;
	}

	// https://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html
	UppLog() << "\n\nTutorial page 3 - The Array class and coefficient-wise operations ";

	UppLog() << "\n\nAccessing values inside an Array";
	{
		ArrayXXf  m(2,2);

		// assign some values coefficient by coefficient
		m(0,0) = 1.0; m(0,1) = 2.0;
		m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0);

		// print values to standard output
		UppLog() << "\n" << m;

		// using the comma-initializer is also allowed
		m << 1.0,2.0,
		   	 3.0,4.0;

		// print values to standard output
		UppLog() << "\n" << m;
	}
	UppLog() << "\n\nAddition and subtraction";
	{
		ArrayXXf a(3,3);
		ArrayXXf b(3,3);
		a << 1,2,3,
		   	 4,5,6,
		   	 7,8,9;
		b << 1,2,3,
		   	 1,2,3,
		   	 1,2,3;

		// Adding two arrays
		UppLog() << "\na + b = " << "\n" << a + b;

		// Subtracting a scalar from an array
		UppLog() << "\na - 2 = " << "\n" << a - 2;
	}
	UppLog() << "\n\nArray multiplication";
	{
		ArrayXXf a(2,2);
		ArrayXXf b(2,2);
		a << 1,2,
		   	 3,4;
		b << 5,6,
		   	 7,8;
		UppLog() << "\na * b = " << "\n" << a * b;
	}
	UppLog() << "\n\nOther coefficient-wise operations";
	{
		ArrayXf a = ArrayXf::Random(5);
		a *= 2;
		UppLog() << "\na =" << "\n" << a;
		UppLog() << "\na.abs() =" << "\n" << a.abs();
		UppLog() << "\na.abs().sqrt() =" << "\n" << a.abs().sqrt();
		UppLog() << "\na.min(a.abs().sqrt()) =" << "\n" << a.min(a.abs().sqrt());
	}
	UppLog() << "\n\nConverting between array and matrix expressions";
	{
		MatrixXf m(2,2);
		MatrixXf n(2,2);
		m << 1,2,
		   	 3,4;
		n << 5,6,
		   	 7,8;

		UppLog() << "\n-- Matrix m*n: --" << "\n" << m * n;
		UppLog() << "\n-- Array m*n: --" << "\n" << m.array() * n.array();
		UppLog() << "\n-- With cwiseProduct: --" << "\n" << m.cwiseProduct(n);
		UppLog() << "\n-- Array m + 4: --" << "\n" << m.array() + 4;
	}
	{
		MatrixXf m(2,2);
		MatrixXf n(2,2);
		m << 1,2,
		     3,4;
		n << 5,6,
		     7,8;

		UppLog() << "\n-- Combination 1: --" << "\n" << (m.array() + 4).matrix() * m;
		UppLog() << "\n-- Combination 2: --" << "\n" << (m.array() * n.array()).matrix() * m;
	}

	// https://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html
	UppLog() << "\n\nTutorial page 4 - Block operations";

	UppLog() << "\n\nUsing block operations";
	{
		Eigen::MatrixXf m(4,4);
		m << 1, 2, 3, 4,
		     5, 6, 7, 8,
		     9,10,11,12,
		   	 13,14,15,16;
		UppLog() << "\nBlock in the middle\n";
		UppLog() << m.block<2,2>(1,1);
		for (ptrdiff_t i = 1; i <= 3; ++i) {
			UppLog() << "\nBlock of size " << i << "x" << i << "\n";
			UppLog() << m.block(0, 0, i, i);
		}
	}
	{
		Array22d m;
		m << 1,2,
		   	 3,4;
		Array44d a = Array44d::Constant(0.6);
		UppLog() << "\nHere is the array a:\n" << a;
		a.block<2,2>(1,1) = m;
		UppLog() << "\nHere is now a with m copied into its central 2x2 block:\n" << a;
		a.block(0,0,2,3) = a.block(2,1,2,3);
		UppLog() << "\nHere is now a with bottom-right 2x3 block copied into top-left 2x2 block:\n" << a;
	}
	UppLog() << "\n\nColumns and rows";
	{
		Eigen::MatrixXf m(3,3);
		m << 1,2,3,
			 4,5,6,
		   	 7,8,9;
		UppLog() << "\nHere is the matrix m:\n" << m;
		UppLog() << "\n2nd Row: " << m.row(1);
		m.col(2) += 3 * m.col(0);
		UppLog() << "\nAfter adding 3 times the first column into the third column, the matrix m is:\n";
		UppLog() << m;
	}
	UppLog() << "\n\nCorner-related operations";
	{
		Eigen::Matrix4f m;
		m << 1, 2, 3, 4,
		   	 5, 6, 7, 8,
		   	 9, 10,11,12,
		   	 13,14,15,16;
		UppLog() << "\nm.leftCols(2) =\n" << m.leftCols(2);
		UppLog() << "\nm.bottomRows<2>() =\n" << m.bottomRows<2>();
		m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose();
		UppLog() << "\nAfter assignment, m = \n" << m;
	}
	UppLog() << "\n\nBlock operations for vectors. Get a segment or fragment";
	{
		Eigen::ArrayXf v(6);
		v << 1, 2, 3, 4, 5, 6;
		UppLog() << "\nv.head(3) =\n" << v.head(3);
		UppLog() << "\nv.tail<3>() = \n" << v.tail<3>();
		v.segment(1,4) *= 2;
		UppLog() << "\nafter 'v.segment(1,4) *= 2', v =\n" << v;
	}

	// https://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html
	UppLog() << "\n\nTutorial page 5 - Advanced initialization";

	UppLog() << "\n\nThe comma initializer";
	{
		RowVectorXd vec1(3);
		vec1 << 1, 2, 3;
		UppLog() << "\nvec1 = " << vec1;

		RowVectorXd vec2(4);
		vec2 << 1, 4, 9, 16;
		UppLog() << "\nvec2 = " << vec2;

		RowVectorXd joined(7);
		joined << vec1, vec2;
		UppLog() << "\njoined = " << joined;

		MatrixXf matA(2, 2);
		matA << 1, 2, 3, 4;
		MatrixXf matB(4, 4);
		matB << matA, matA/10, matA/10, matA;
		UppLog() << matB;

		Matrix3f m;
		m.row(0) << 1, 2, 3;
		m.block(1,0,2,2) << 4, 5, 7, 8;
		m.col(2).tail(2) << 6, 9;
		UppLog() << m;
	}
	UppLog() << "\n\nSpecial matrices and arrays";
	{
		UppLog() << "\nA fixed-size array:\n";
		Array33f a1 = Array33f::Zero();
		UppLog() << a1 << "\n\n";

		UppLog() << "\nA one-dimensional dynamic-size array:\n";
		ArrayXf a2 = ArrayXf::Zero(3);
		UppLog() << a2 << "\n\n";

		UppLog() << "\nA two-dimensional dynamic-size array:\n";
		ArrayXXf a3 = ArrayXXf::Zero(3, 4);
		UppLog() << a3 << "\n";

		UppLog() << "\nA two-dimensional dynamic-size array set to 1.23:\n";
		MatrixXd a4 = MatrixXd::Constant(3, 4, 1.23);
		UppLog() << a4 << "\n";

		ArrayXXd table(10, 4);
		table.col(0) = ArrayXd::LinSpaced(10, 0, 90);
		table.col(1) = M_PI / 180 * table.col(0);
		table.col(2) = table.col(1).sin();
		table.col(3) = table.col(1).cos();
		UppLog() << "\n  Degrees   Radians      Sine    Cosine\n";
		UppLog() << table;

		const ptrdiff_t size = 6;
		MatrixXd mat1(size, size);
		mat1.topLeftCorner(size/2, size/2)     = MatrixXd::Zero(size/2, size/2);
		mat1.topRightCorner(size/2, size/2)    = MatrixXd::Identity(size/2, size/2);
		mat1.bottomLeftCorner(size/2, size/2)  = MatrixXd::Identity(size/2, size/2);
		mat1.bottomRightCorner(size/2, size/2) = MatrixXd::Zero(size/2, size/2);
		UppLog() << "\n" << mat1;

		MatrixXd mat2(size, size);
		mat2.topLeftCorner(size/2, size/2).setZero();
		mat2.topRightCorner(size/2, size/2).setIdentity();
		mat2.bottomLeftCorner(size/2, size/2).setIdentity();
		mat2.bottomRightCorner(size/2, size/2).setZero();
		UppLog() << "\n" << mat2;

		MatrixXd mat3(size, size);
		mat3 << MatrixXd::Zero(size/2, size/2), MatrixXd::Identity(size/2, size/2),
		        MatrixXd::Identity(size/2, size/2), MatrixXd::Zero(size/2, size/2);
		UppLog() << "\n" << mat3;
	}
	UppLog() << "\n\nUsage as temporary objects";
	{
		MatrixXd m = MatrixXd::Random(3,3);
		m = (m + MatrixXd::Constant(3,3,1.2)) * 50;
		UppLog() << "\nm =\n" << m;
		VectorXd v(3);
		v << 1, 2, 3;
		UppLog() << "\nm * v =\n" << m * v;
	}
	{
		MatrixXf mat = MatrixXf::Random(2, 3);
		UppLog() << mat;
		mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat;
		UppLog() << mat;
	}

	// https://eigen.tuxfamily.org/dox/group__TutorialLinearAlgebra.html
	UppLog() << "\n\nTutorial page 6 - Linear algebra and decompositions";

	UppLog() << "\n\nBasic linear solving	Ax = b";
	{
		Matrix3f A;
		Vector3f b;
		A << 1, 2, 3,
			 4, 5, 6,
			 7, 8,10;
		b << 3, 3, 4;
		UppLog() << "\nHere is the matrix A:\n" << A;
		UppLog() << "\nHere is the vector b:\n" << b;
		Vector3f x = A.colPivHouseholderQr().solve(b);
		UppLog() << "\nThe solution is:\n" << x;
	}
	{
		Matrix2f A, b;
		A << 2, -1, -1, 3;
		b << 1, 2, 3, 1;
		UppLog() << "\nHere is the matrix A:\n" << A;
		UppLog() << "\nHere is the right hand side b:\n" << b;
		Matrix2f x = A.ldlt().solve(b);
		UppLog() << "\nThe solution is:\n" << x;
	}
	UppLog() << "\n\nChecking if a solution really exists";
	{
		MatrixXd A = MatrixXd::Random(100,100);
		MatrixXd b = MatrixXd::Random(100,50);
		MatrixXd x = A.fullPivLu().solve(b);
		double relative_error = (A*x - b).norm() / b.norm(); // norm() is L2 norm
		UppLog() << "\nThe relative error is:\n" << relative_error;
	}
	UppLog() << "\n\nComputing eigenvalues and eigenvectors";
	{
		Matrix2f A;
		A << 1, 2, 2, 3;
		UppLog() << "\nHere is the matrix A:\n" << A;
		SelfAdjointEigenSolver<Matrix2f> eigensolver(A);
		UppLog() << "\nThe eigenvalues of A are:\n" << eigensolver.eigenvalues();
		UppLog() << "\nHere's a matrix whose columns are eigenvectors of A "
		    << "corresponding to these eigenvalues:\n"
		    << eigensolver.eigenvectors();
	}
	UppLog() << "\n\nComputing inverse and determinant";
	{
		Matrix3f A;
		A << 1, 2, 1,
		     2, 1, 0,
		    -1, 1, 2;
		UppLog() << "\nHere is the matrix A:\n" << A;
		UppLog() << "\nThe determinant of A is " << A.determinant();
		UppLog() << "\nThe inverse of A is:\n" << A.inverse();
	}
	UppLog() << "\n\nLeast squares solving";
	{
		MatrixXf A = MatrixXf::Random(5, 2);
		UppLog() << "\nHere is the matrix A:\n" << A;
		VectorXf b = VectorXf::Random(5);
		UppLog() << "\nHere is the right hand side b:\n" << b;
		UppLog() << "\nThe least-squares solution is:\n"
		       << A.jacobiSvd(ComputeThinU | ComputeThinV).solve(b);
	}
	UppLog() << "\n\nSeparating the computation from the construction";
	{
		Matrix2f A, b;
		LLT<Matrix2f> llt;
		A << 2, -1, -1, 3;
		b << 1, 2, 3, 1;
		UppLog() << "\nHere is the matrix A:\n" << A;
		UppLog() << "\nHere is the right hand side b:\n" << b;
		UppLog() << "\nComputing LLT decomposition...";
		llt.compute(A);
		UppLog() << "\nThe solution is:\n" << llt.solve(b);
		A(1,1)++;
		UppLog() << "\nThe matrix A is now:\n" << A;
		UppLog() << "\nComputing LLT decomposition...";
		llt.compute(A);
		UppLog() << "\nThe solution is now:\n" << llt.solve(b);
	}
	UppLog() << "\n\nRank-revealing decompositions";
	{
		Matrix3f A;
		A << 1, 2, 5,
		     2, 1, 4,
		     3, 0, 3;
		UppLog() << "\nHere is the matrix A:\n" << A;
		FullPivLU<Matrix3f> lu_decomp(A);
		UppLog() << "\nThe rank of A is " << lu_decomp.rank();
		UppLog() << "\nHere is a matrix whose columns form a basis of the null-space of A:\n"
		    << lu_decomp.kernel();
		UppLog() << "\nHere is a matrix whose columns form a basis of the column-space of A:\n"
		    << lu_decomp.image(A); // yes, have to pass the original A
	}
	{
		Matrix2d A;
		A << 2, 1,
		     2, 0.9999999999;
		FullPivLU<Matrix2d> lu(A);
		UppLog() << "\nBy default, the rank of A is found to be " << lu.rank();
		lu.setThreshold(1e-5);
		UppLog() << "\nWith threshold 1e-5, the rank of A is found to be " << lu.rank();
	}

	// https://eigen.tuxfamily.org/dox/group__TutorialReductionsVisitorsBroadcasting.html
	UppLog() << "\n\nTutorial page 7 - Reductions, visitors and broadcasting";

	UppLog() << "\n\nReductions";
	{
		Eigen::Matrix2d mat;
		mat << 1, 2,
			   3, 4;
		UppLog() << "\nHere is mat.sum():       " << mat.sum();
		UppLog() << "\nHere is mat.prod():      " << mat.prod();
		UppLog() << "\nHere is mat.mean():      " << mat.mean();
		UppLog() << "\nHere is mat.minCoeff():  " << mat.minCoeff();
		UppLog() << "\nHere is mat.maxCoeff():  " << mat.maxCoeff();
		UppLog() << "\nHere is mat.trace():     " << mat.trace();
	}
	UppLog() << "\n\nNorm computations";
	{
		VectorXf v(2);
		MatrixXf m(2,2), n(2,2);

		v << -1,
		   	  2;

		m << 1,-2,
			-3, 4;

		UppLog() << "\nv.squaredNorm() = " << v.squaredNorm();
		UppLog() << "\nv.norm() = " << v.norm();
		UppLog() << "\nv.lpNorm<1>() = " << v.lpNorm<1>();
		UppLog() << "\nv.lpNorm<Infinity>() = " << v.lpNorm<Infinity>();

		UppLog() << "\n";
		UppLog() << "\nm.squaredNorm() = " << m.squaredNorm();
		UppLog() << "\nm.norm() = " << m.norm();
		UppLog() << "\nm.lpNorm<1>() = " << m.lpNorm<1>();
		UppLog() << "\nm.lpNorm<Infinity>() = " << m.lpNorm<Infinity>();
	}
	UppLog() << "\n\nBoolean reductions";
	{
		ArrayXXf a(2,2);

		a << 1,2,
		   	 3,4;

		UppLog() << "\n(a > 0).all()   = " << (a > 0).all();
		UppLog() << "\n(a > 0).any()   = " << (a > 0).any();
		UppLog() << "\n(a > 0).count() = " << (a > 0).count();
		UppLog() << "\n";
		UppLog() << "\n(a > 2).all()   = " << (a > 2).all();
		UppLog() << "\n(a > 2).any()   = " << (a > 2).any();
		UppLog() << "\n(a > 2).count() = " << (a > 2).count();
	}
	UppLog() << "\n\nVisitors";
	{
		Eigen::MatrixXf m(2,2);

		m << 1, 2,
		   	 3, 4;

		//get location of maximum
		MatrixXf::Index maxRow, maxCol;
		float max = m.maxCoeff(&maxRow, &maxCol);

		//get location of minimum
		MatrixXf::Index minRow, minCol;
		float min = m.minCoeff(&minRow, &minCol);

		UppLog() << "\nMax: " << max <<  ", at: " << maxRow << "," << maxCol;
		UppLog() << "\nMin: " << min << ", at: " << minRow << "," << minCol;
	}
	UppLog() << "\n\nPartial reductions";
	{
		Eigen::MatrixXf mat(2,4);
		mat << 1, 2, 6, 9,
		       3, 1, 7, 2;

		UppLog() << "\nColumn's maximum: \n" << mat.colwise().maxCoeff();
	}
	{
		Eigen::MatrixXf mat(2,4);
		mat << 1, 2, 6, 9,
		       3, 1, 7, 2;

		UppLog() << "\nRow's maximum: \n" << mat.rowwise().maxCoeff();
	}
	UppLog() << "\n\nCombining partial reductions with other operations";
	{
		MatrixXf mat(2,4);
		mat << 1, 2, 6, 9,
		       3, 1, 7, 2;

		MatrixXf::Index   maxIndex;
		float maxNorm = mat.colwise().sum().maxCoeff(&maxIndex);

		UppLog() << "\nMaximum sum at position " << maxIndex;

		UppLog() << "\nThe corresponding vector is: ";
		UppLog() << "\n" << mat.col( maxIndex );
		UppLog() << "\nAnd its sum is is: " << maxNorm;
	}
	UppLog() << "\n\nBroadcasting";
	{
		Eigen::MatrixXf mat(2,4);
		Eigen::VectorXf v(2);

		mat << 1, 2, 6, 9,
		       3, 1, 7, 2;

		v << 0,
		     1;

		//add v to each column of m
		mat.colwise() += v;

		UppLog() << "\nBroadcasting result: ";
		UppLog() << "\n" << mat;
	}
	{
		Eigen::MatrixXf mat(2,4);
		Eigen::VectorXf v(4);

		mat << 1, 2, 6, 9,
		       3, 1, 7, 2;

		v << 0,1,2,3;

		//add v to each row of m
		mat.rowwise() += v.transpose();

		UppLog() << "\nBroadcasting result: ";
		UppLog() << "\n" << mat;
	}
	UppLog() << "\n\nCombining broadcasting with other operations";
	{
		Eigen::MatrixXf m(2,4);
		Eigen::VectorXf v(2);

		m << 1, 23, 6, 9,
		   	 3, 11, 7, 2;

		v << 2,
		     3;

		MatrixXf::Index index;
		// find nearest neighbour
		(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);

		UppLog() << "\nNearest neighbour is column " << index << ":";
		UppLog() << "\n" << m.col(index);
	}

	UppLog() << "\n\nSerializing tests";
	{
		SerialTest serialTest, serialTest_j, serialTest_x, serialTest_s;
		serialTest.m << 1, 2,
		     			4, 8;
		serialTest.v << 1, 2, 4;

		StoreAsJsonFile(serialTest, GetExeDirFile("Json.txt"));
		LoadFromJsonFile(serialTest_j, GetExeDirFile("Json.txt"));
		UppLog() << "\nJSON demo";
		serialTest_j.Print();

		StoreAsXMLFile(serialTest, "XMLdata", GetExeDirFile("Xml.txt"));
		LoadFromXMLFile(serialTest_x, GetExeDirFile("Xml.txt"));
		UppLog() << "\nXML demo";
		serialTest_x.Print();

		StoreToFile(serialTest, GetExeDirFile("Serial.dat"));
		LoadFromFile(serialTest_s, GetExeDirFile("Serial.dat"));
		UppLog() << "\nSerialization demo";
		serialTest_s.Print();
	}

	NonLinearTests();

	FFTTests();

	#ifdef flagDEBUG
	Cout() << "\nPress enter key to end";
	ReadStdIn();
	#endif
}


#include "Euclidean.h"

#include <boost/multiprecision/cpp_int.hpp>
using namespace boost::multiprecision;

Euclidean::Euclidean()
{};

Euclidean::~Euclidean()
{};

int256_t Euclidean::extendedEuclidean(int256_t a, int256_t b, int256_t* x, int256_t* s)
{
  if ((a == 0) || (b == 0))
  {
    return 0;
  }

  int256_t q = 0;
  int256_t r = 0;

  q = a / b;

  //remainder
  r = a % b;

  int256_t x_tmp = *x;
  int256_t s_tmp = *s;
  if (r != 0)
  {
    extendedEuclidean(b, r, &x_tmp, &s_tmp);
  }

  if (r == 0)
  {
    *x = 0;
    *s = 1;

    return b;
  }

  *x = s_tmp;
  *s = x_tmp - (q * s_tmp);

  return b;
}

int256_t Euclidean::euclidean(int256_t a, int256_t b)
{

  if ((a == 0) || (b == 0))
  {
    return 0;
  }

  int256_t q;
  int256_t r;

  do
  {
    q = a / b;
    r = a % b;

    a = b;
    b = r;
  } while (r != 0);

  return a;
}


// OpenTissue, A toolbox for physical based simulation and animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <OpenTissue/configuration.h>
#include <OpenTissue/core/spline/spline.h>

#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>

// Boost Test declaration and Checking macros
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/floating_point_comparison.hpp>

typedef OpenTissue::spline::MathTypes<double, size_t>    math_types;
typedef math_types::vector_type                                vector_type;
typedef std::vector<double>                                    knot_container;

BOOST_AUTO_TEST_SUITE(opentissue_spline_nonzero_compute_basis);

BOOST_AUTO_TEST_CASE(test_compute_nonzero_basis)
{
  knot_container U;

  U.push_back(0.0);
  U.push_back(0.0);
  U.push_back(0.0);  //k = 3
  U.push_back(1.0);
  U.push_back(2.0);
  U.push_back(3.0);
  U.push_back(4.0);  // n = 6  => |P| = 7
  U.push_back(5.0);
  U.push_back(5.0);
  U.push_back(5.0);  // m = 9  => |U| = 10

  // Indices of basis functions belongs to the interval [0..n]

  double const tolerance = 0.00001;

  // Verify if invalid arguments get caught
  {
    vector_type N;
    BOOST_CHECK_THROW( OpenTissue::spline::detail::compute_nonzero_basis(-1.0, 3, U, N), std::invalid_argument );
    BOOST_CHECK_THROW( OpenTissue::spline::detail::compute_nonzero_basis( 6.0, 3, U, N), std::invalid_argument );
    BOOST_CHECK_THROW( OpenTissue::spline::detail::compute_nonzero_basis( 2.5, 0, U, N), std::invalid_argument );
    BOOST_CHECK_THROW( OpenTissue::spline::detail::compute_nonzero_basis( 1.0, 10, U, N), std::invalid_argument );
  }
  // u-parameter at lower bound
  {
    vector_type N;
    double const u = 0.0;
    BOOST_CHECK_NO_THROW( OpenTissue::spline::detail::compute_nonzero_basis(u, 3, U, N) );
    double const & b1 = N(0);
    double const & b2 = N(1);
    double const & b3 = N(2);
    BOOST_CHECK_CLOSE(b1, 1.0, tolerance);
    BOOST_CHECK_CLOSE(b2, 0.0, tolerance);
    BOOST_CHECK_CLOSE(b3, 0.0, tolerance);
  }
  // u-parameter at half-way
  {
    vector_type N;
    double const u = 2.5;
    BOOST_CHECK_NO_THROW( OpenTissue::spline::detail::compute_nonzero_basis(u, 3, U, N) );
    double const & b1 = N(0);
    double const & b2 = N(1);
    double const & b3 = N(2);
    BOOST_CHECK_CLOSE(b1, 1.0/8.0, tolerance);
    BOOST_CHECK_CLOSE(b2, 6.0/8.0, tolerance);
    BOOST_CHECK_CLOSE(b3, 1.0/8.0, tolerance);
  }
  // u-parameter at upper bound
  {
    vector_type N;
    double const u = 5.0;
    BOOST_CHECK_NO_THROW( OpenTissue::spline::detail::compute_nonzero_basis(u, 3, U, N) );
    double const & b1 = N(0);
    double const & b2 = N(1);
    double const & b3 = N(2);
    BOOST_CHECK_CLOSE(b1, 0.0, tolerance);
    BOOST_CHECK_CLOSE(b2, 0.0, tolerance);
    BOOST_CHECK_CLOSE(b3, 1.0, tolerance);
  }
}

BOOST_AUTO_TEST_SUITE_END();


#include <Eigen/Core>
#include <Eigen/Eigenvalues>

#include <iostream>
#include <random>

class MultiVariateNormal
{
public:
  MultiVariateNormal(const Eigen::VectorXd mean, const Eigen::MatrixXd covariance)
  : mean_(mean), covariance_(covariance)
  {
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eigen_solver(covariance_);
    transform_ = eigen_solver.eigenvectors() * eigen_solver.eigenvalues().cwiseSqrt().asDiagonal();
  }
  double pdf(const Eigen::VectorXd & x) const
  {
    double n = x.rows();
    double a = (x - mean_).transpose() * covariance_.inverse() * (x - mean_);
    double b = std::pow(std::sqrt(2 * M_PI), n) * std::sqrt(covariance_.determinant());
    return std::exp(-0.5 * a) / b;
  }

  Eigen::VectorXd operator()() const
  {
    static std::random_device seed;
    static std::mt19937 engine(seed());
    static std::normal_distribution<> dist;

    return mean_ + transform_ * Eigen::VectorXd{mean_.size()}.unaryExpr([&](auto x) { return dist(engine); });
  }
  void setMean(const Eigen::VectorXd mean) { mean_ = mean; }
  void setCovariance(const Eigen::MatrixXd covariance) { covariance_ = covariance; }

private:
  Eigen::VectorXd mean_;
  Eigen::MatrixXd covariance_;
  Eigen::MatrixXd transform_;
};

int main(int argc, char ** argv)
{
  Eigen::VectorXd mean(2);
  Eigen::MatrixXd covariance(2, 2);

  mean << 0.0, 0.0;
  covariance << 1.0, 0.1, 0.1, 1.0;

  MultiVariateNormal multi_variate_normal(mean, covariance);

  Eigen::VectorXd x(2);
  x << 0.2, 0.3;
  std::cout << multi_variate_normal.pdf(x) << std::endl;

  return 0;
}


#define BOOST_TEST_MODULE FourierTransformTest
#include <boost/test/unit_test.hpp>

// For IO
#include <stdlib.h>
#include <math.h>
#include <cmath>
#include <iostream>
#include <unistd.h>

// For measuring elapsed time
#include <chrono>

// For Random Float Generator
#include <time.h>

// For object under test
#include "ofdmfft.h"

#define FFT_DIFFERENCE_THRESHOLD 0.0000000000001
#define FFT_NUMERICAL_THRESHOLD 0.0000000001

// Test FFT & IFFT
/**
* Test FFT & IFFT
* @todo: Unify the printing standard and formating
*/
BOOST_AUTO_TEST_SUITE(FOURIER_TRANSFORMS)

/**
* Generate random data (floats) Put it throguh IFFT.
* Copy the time domain samples into FFT input buffer.
* Execute and check the input and output are within a
* threshold value.
*
*/
BOOST_AUTO_TEST_CASE(IFFTtoFFT)
{
    printf("\nTesting IFFT to IFFT...\n");
    printf("\nInverse Fourier transform:\n");

    // Setup random float generator
    srand( (unsigned)time( NULL ) );

    uint16_t nPoints = 512;
    uint16_t pilotToneStep = 16;

    ofdmFFT ifft(nPoints, FFTW_BACKWARD, pilotToneStep);
    ofdmFFT fft(nPoints, FFTW_FORWARD, pilotToneStep);

    // Generate random floats
    for (uint16_t i = 0; i < nPoints; i++)
    {
        ifft.in[i][0] = (double) rand()/RAND_MAX;
        ifft.in[i][1] = (double) rand()/RAND_MAX;
    }

    // Measure wall time of the ifft execution.
    auto start = std::chrono::steady_clock::now();
    ifft.ComputeTransform();
    auto end = std::chrono::steady_clock::now();

    std::cout << "ifft Elapsed time in nanoseconds: "
        << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
        << " ns" << std::endl;

    /*
    for (uint16_t i = 0; i < nPoints; i++)
    {
        printf("Time: %3d %+9.5f j%+9.5f \n", i, ifft.out[i][0], ifft.out[i][1]);
    }
    */

    printf("\nFourier Transform:\n");
    // Assign the output of ifft to the input of fft
    for (uint16_t i = 0; i < nPoints; i++)
    {
        fft.in[i][0] = ifft.out[i][0];
        fft.in[i][1] = ifft.out[i][1];
    }

    // Measure wall time of the fft execution.
    start = std::chrono::steady_clock::now();
    fft.ComputeTransform();
    end = std::chrono::steady_clock::now();

    std::cout << "fft Elapsed time in nanoseconds: "
        << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
        << " ns" << std::endl;

    // Normalize samples
    for (uint16_t i = 0; i < nPoints; i++)
    {
        fft.out[i][0] *= 1./nPoints;
        fft.out[i][1] *= 1./nPoints;
    }

    // Print input and output buffers
    for (uint16_t i = 0; i < nPoints; i++)
    {
        /*
        printf("Recovered Sample(time domain) %3d %+9.5f j%+9.5f Input to IFFT vs. %+9.5f j%+9.5f Output of FFT\n",
        i, ifft.in[i][0], ifft.in[i][1], fft.out[i][0], fft.out[i][1]);
        */

        // Check if real and complex element match within defined precision.
        BOOST_CHECK_MESSAGE(
         ( (std::abs( ifft.in[i][0] - fft.out[i][0] ) <= FFT_DIFFERENCE_THRESHOLD ) ||
         (  std::abs( ifft.in[i][1] - fft.out[i][1] ) <= FFT_DIFFERENCE_THRESHOLD )),
         "Values vary more than threshold! - Occured at index: " << i );

    }
    fftw_cleanup();
}

/**
* Generate cosine of one frequency in time domain, put it throguh IFFT.
* Copy the time domain samples into FFT input buffer.
* Execute and check the input and output are within a
* threshold value. Each time changing the frequency of
* cosine.
*
*/
BOOST_AUTO_TEST_CASE(IFFTtoFFTCosine)
{
    printf("\nTesting IFFT to FFT Using Cosine...\n");

    // Setup random float generator
    srand( (unsigned)time( NULL ) );

    // Initialize fft object of size 512
    uint16_t nPoints = 512;
    uint16_t pilotToneStep = 16;

    ofdmFFT ifft(nPoints, FFTW_BACKWARD, pilotToneStep);
    ofdmFFT fft(nPoints, FFTW_FORWARD, pilotToneStep);

    for(uint16_t j = 0; j < nPoints; j++)
    {
        // Generate Cosine wave in freq domain
        for(uint16_t i = 1; i < nPoints; i++)
        {
            // Insert value at desired frequency
            if (i == j)
            {
                ifft.in[i][0] = nPoints/2;
                ifft.in[i][1] = 0;
            }

            // Modify the negative frequency
            else if (i == nPoints-j)
            {
                ifft.in[i][0] = nPoints/2;
                ifft.in[i][1] = 0;
            }
            // Fill with 0 otherwise
            else
            {
                ifft.in[i][0] = nPoints/2;
                ifft.in[i][1] = 0;
            }

        }
        // Inverse Fourier transform
        //printf("\nInverse Fourier transform:\n");

        // Measure wall time of the ifft execution.
        auto start = std::chrono::steady_clock::now();
        ifft.ComputeTransform();
        auto end = std::chrono::steady_clock::now();

        // Print elapsed time
        /*
        std::cout << "ifft Elapsed time in nanoseconds: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;
        */

        // Print fft data
        /*
        for (uint16_t i = 0; i < nPoints; i++)
        {
            printf("Time: %3d %+9.5f j%+9.5f \n", i, ifft.out[i][0], ifft.out[i][1]);
        }
        */

        // Fourier Transform
        // printf("\nFourier Transform:\n");
        // Assign the output of forward fft to the input of backward fft
        for (uint16_t i = 0; i < nPoints; i++)
        {
            fft.in[i][0] = ifft.out[i][0];
            fft.in[i][1] = ifft.out[i][1];
        }

        // Measure wall time of the fft execution.
        start = std::chrono::steady_clock::now();
        fft.ComputeTransform();
        end = std::chrono::steady_clock::now();

        // Print elapsed time
        /*
        std::cout << "fft Elapsed time in nanoseconds: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;
        */

        // Print input and output buffers
        for (uint16_t i = 0; i < nPoints; i++)
        {
            // Check if real and complex element match within defined precision.
            BOOST_CHECK_MESSAGE(
            ( (std::abs( ifft.in[i][0] - fft.out[i][0] ) <= FFT_DIFFERENCE_THRESHOLD ) ||
            (  std::abs( ifft.in[i][1] - fft.out[i][1] ) <= FFT_DIFFERENCE_THRESHOLD )),
            "Values vary more than threshold! - Occured at: index j = " << j << " & Index i = " << i );
        }

    }
    fftw_cleanup();
}

/**
* Generate random data (floats) Put it throguh FFT.
* Copy the frequency domain samples into IFFT input buffer.
* Execute and check the input and output are within a
* threshold value.
*
*/
BOOST_AUTO_TEST_CASE(FFTtoIFFT)
{
    printf("\nTesting FFT to IFFT...\n");
    printf("\nFourier transform:\n");

    // Setup random float generator
    srand( (unsigned)time( NULL ) );

    uint16_t nPoints = 512;
    uint16_t pilotToneStep = 16;

    ofdmFFT forwardfft(nPoints, FFTW_FORWARD, pilotToneStep);
    ofdmFFT backwardfft(nPoints, FFTW_BACKWARD, pilotToneStep);

    // Generate random floats
    for (uint16_t i = 0; i < nPoints; i++)
    {
        forwardfft.in[i][0] = (double) rand()/RAND_MAX;
        forwardfft.in[i][1] = (double) rand()/RAND_MAX;
    }

    // Measure wall time of the ifft execution.
    auto start = std::chrono::steady_clock::now();
    forwardfft.ComputeTransform();
    auto end = std::chrono::steady_clock::now();

    // Print elapsed time
    std::cout << "forwardfft Elapsed time in nanoseconds: "
        << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
        << " ns" << std::endl;

    /*
    for (uint16_t i = 0; i < nPoints; i++)
    {
        printf("freq: %3d %+9.5f j%+9.5f \n", i, forwardfft.out[i][0], forwardfft.out[i][1]);
    }
    */

    printf("\nInverse Fourier Transform:\n");
    // Assign the output of forward fft to the input of backward fft
    for (uint16_t i = 0; i < nPoints; i++)
    {
        backwardfft.in[i][0] = forwardfft.out[i][0];
        backwardfft.in[i][1] = forwardfft.out[i][1];
    }

    // Measure wall time of the fft execution.
    start = std::chrono::steady_clock::now();
    backwardfft.ComputeTransform();
    end = std::chrono::steady_clock::now();

    std::cout << "backwardfft Elapsed time in nanoseconds: "
        << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
        << " ns" << std::endl;

    // Normalize samples
    for (uint16_t i = 0; i < nPoints; i++)
    {
        backwardfft.out[i][0] *= 1./nPoints;
        backwardfft.out[i][1] *= 1./nPoints;
    }

    // Print input and output buffers
    for (uint16_t i = 0; i < nPoints; i++)
    {
        //printf("Recovered Sample(time domain) %3d %+9.5f j%+9.5f Input to fft vs. %+9.5f j%+9.5f Output of IFFT\n",
        //i, forwardfft.in[i][0], forwardfft.in[i][1], backwardfft.out[i][0], backwardfft.out[i][1]);

        // Check if real and complex element match within defined precision.
        BOOST_CHECK_MESSAGE(
         ( (std::abs( forwardfft.in[i][0] - backwardfft.out[i][0] ) <= FFT_DIFFERENCE_THRESHOLD ) ||
         (  std::abs( forwardfft.in[i][1] - backwardfft.out[i][1] ) <= FFT_DIFFERENCE_THRESHOLD )),
         "Values vary more than threshold! - Occured at index: " << i );

    }
    fftw_cleanup();
}

/**
* Generate cosine of one frequency in time domain, put it throguh FFT.
* Copy the frequency domain samples into IFFT input buffer.
* Execute and check the input and output are within a
* threshold value. Each time changing the frequency of
* cosine.
*
*/
BOOST_AUTO_TEST_CASE(FFTtoIFFTCosine)
{
    printf("\nTesting FFT to IFFT Using Cosine...\n");

    // Setup random float generator
    srand( (unsigned)time( NULL ) );

    // Initialize fft object of size 512
    uint16_t nPoints = 512;
    uint16_t pilotToneStep = 16;

    ofdmFFT forwardfft(nPoints, FFTW_FORWARD, pilotToneStep);
    ofdmFFT backwardfft(nPoints, FFTW_BACKWARD, pilotToneStep);

    for(uint16_t j = 0; j < nPoints; j++)
    {
        // Generate Cosine wave in time domain
        for(uint16_t i = 0; i < nPoints; i++)
        {
            forwardfft.in[i][0] = cos(j * 2*M_PI*i/nPoints);
            forwardfft.in[i][1] = 0;
        }

        // Fourier transform:
        //printf("\nFourier transform:\n");

        // Measure wall time of the ifft execution.
        auto start = std::chrono::steady_clock::now();
        forwardfft.ComputeTransform();
        auto end = std::chrono::steady_clock::now();

        // Print elapsed time
        /*
        std::cout << "forwardfft Elapsed time in nanoseconds: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;
        */

        // Print fft data
        for (uint16_t i = 1; i < nPoints; i++)
        {
            //printf("Freq: %3d %+9.5f j%+9.5f \n", i, forwardfft.out[i][0], forwardfft.out[i][1]);

            if(i==j)
            {
                // Check if real and complex element match within defined precision.
                BOOST_CHECK_MESSAGE( ( forwardfft.out[i][0] > FFT_NUMERICAL_THRESHOLD ),
                "Value is below threshold! - Occured at: index j = " << j << " & Index i = " << i );
            }
            else if(i == (nPoints -j))
            {
                // Check if real and complex element match within defined precision.
                BOOST_CHECK_MESSAGE( ( forwardfft.out[i][0] > FFT_NUMERICAL_THRESHOLD ),
                "Value is below threshold! - Occured at: index j = " << j << " & Index i = " << i);
            }
            else
            {
                // Check if real and complex element match within defined precision.
                BOOST_CHECK_MESSAGE( ( forwardfft.out[i][0] < FFT_NUMERICAL_THRESHOLD ),
                "Value is above threshold! - Occured at: index j = " << j << " & Index i = " << i );
            }
         }

        // Inverse Fourier Transform
        // printf("\nInverse Fourier Transform:\n");
        // Assign the output of forward fft to the input of backward fft
        for (uint16_t i = 0; i < nPoints; i++)
        {
            backwardfft.in[i][0] = forwardfft.out[i][0];
            backwardfft.in[i][1] = forwardfft.out[i][1];
        }

        // Measure wall time of the fft execution.
        start = std::chrono::steady_clock::now();
        backwardfft.ComputeTransform();
        end = std::chrono::steady_clock::now();

        // Print elapsed time
        /*
        std::cout << "backwardfft Elapsed time in nanoseconds: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;
        */

        // Normalize
        for (uint16_t i = 0; i < nPoints; i++)
        {
            backwardfft.out[i][0] *= 1./nPoints;
            backwardfft.out[i][1] *= 1./nPoints;
        }

        // Print input and output buffers
        for (uint16_t i = 0; i < nPoints; i++)
        {
            // Check if real and complex element match within defined precision.
            BOOST_CHECK_MESSAGE(
            ( (std::abs( forwardfft.in[i][0] - backwardfft.out[i][0] ) <= FFT_DIFFERENCE_THRESHOLD ) ||
            (  std::abs( forwardfft.in[i][1] - backwardfft.out[i][1] ) <= FFT_DIFFERENCE_THRESHOLD )),
            "Values vary more than threshold! - Occured at: index j = " << j << " & Index i = " << i );
        }

    }
    fftw_cleanup();
}

/**
* Generate random data (floats) Put it throguh FFT.
* Copy the frequency domain samples into IFFT input buffer.
* Execute and check the input and output are within a
* threshold value. Each time reconfiguring the size of
* fft.
*
*/
BOOST_AUTO_TEST_CASE(Reconfiguration)
{
    printf("\nTesting Object Reconfiguration...\n");

    // Setup random float generator
    srand( (unsigned)time( NULL ) );

    // Initialize fft object with size of 1
    uint16_t nPoints = 1;
    uint16_t pilotToneStep = 16;
    ofdmFFT forwardfft(nPoints, FFTW_FORWARD, pilotToneStep);
    ofdmFFT backwardfft(nPoints, FFTW_BACKWARD, pilotToneStep);

    int PowOf2Arr[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
    int nTestSizes = sizeof(PowOf2Arr) / sizeof(PowOf2Arr[0]);

    // For each array size
    for(uint16_t j = 0; j < nTestSizes; j++)
    {
        printf("\nTesting %d Point FFT\n",PowOf2Arr[j]);
        forwardfft.Configure(PowOf2Arr[j], FFTW_FORWARD,pilotToneStep);
        backwardfft.Configure(PowOf2Arr[j], FFTW_BACKWARD, pilotToneStep);
        // Generate random floats

        for (uint16_t i = 0; i < PowOf2Arr[j]; i++)
        {
            forwardfft.in[i][0] = (double) rand()/RAND_MAX;
            forwardfft.in[i][1] = (double) rand()/RAND_MAX;
        }

        // Measure wall time of the ifft execution.
        auto start = std::chrono::steady_clock::now();
        forwardfft.ComputeTransform();
        auto end = std::chrono::steady_clock::now();

        std::cout << "Fourier transform elapsed time: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;

        // Print Data output of forward FFT
        /*
        for (uint16_t i = 0; i < PowOf2Arr[j]; i++)
        {
            printf("Freq: %3d %+9.5f j%+9.5f \n", i, forwardfft.out[i][0], forwardfft.out[i][1]);
        }
        */

        // Assign the output of forward fft to the input of backward fft
        for (uint16_t i = 0; i < PowOf2Arr[j]; i++)
        {
            backwardfft.in[i][0] = forwardfft.out[i][0];
            backwardfft.in[i][1] = forwardfft.out[i][1];
        }

        // Measure wall time of the fft execution.
        start = std::chrono::steady_clock::now();
        backwardfft.ComputeTransform();
        end = std::chrono::steady_clock::now();

        std::cout << "Inverse Fourier Transform elapsed time: "
            << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count()
            << " ns" << std::endl;

        // Normalize
        for (uint16_t i = 0; i < PowOf2Arr[j]; i++)
        {
            backwardfft.out[i][0] *= 1./PowOf2Arr[j];
            backwardfft.out[i][1] *= 1./PowOf2Arr[j];
        }

        // Print input and output buffers
        for (uint16_t i = 0; i < PowOf2Arr[j]; i++)
        {
            //printf("Recovered Sample: %3d %+9.5f j%+9.5f Input to fft vs. %+9.5f j%+9.5f Output of IFFT\n",
            //i, forwardfft.in[i][0], forwardfft.in[i][1], backwardfft.out[i][0], backwardfft.out[i][1]);

            // Check if real and complex element match within defined precision of each other
            BOOST_CHECK_MESSAGE(
            ( (std::abs( forwardfft.in[i][0] - backwardfft.out[i][0] ) <= FFT_DIFFERENCE_THRESHOLD ) ||
            (  std::abs( forwardfft.in[i][1] - backwardfft.out[i][1] ) <= FFT_DIFFERENCE_THRESHOLD )),
            "Values vary more than threshold! - Occured at: index j = " << j << " & Index i = " << i );

        }
    }
    fftw_cleanup();
}
BOOST_AUTO_TEST_SUITE_END()


/** Test cases for Segment class.
 *
 */

#include "segment.h"

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE SegmentTest
#include <boost/test/unit_test.hpp>

#include <iostream>

using namespace qmicad::tmfsc;
using namespace std;
BOOST_AUTO_TEST_CASE(basic)
{
    point p = {0, 0};
    point q = {10, 10};
    Segment pq(p, q);

    BOOST_CHECK(pq.length() == sqrt(200));
    BOOST_CHECK_CLOSE(pq.angle(), 3.1415926536/4, 1E-4);

    svec unitvec = pq.unitVect();
    BOOST_CHECK_CLOSE(unitvec(0), 1/sqrt(2), 1E-3);
    BOOST_CHECK_CLOSE(unitvec(1), 1/sqrt(2), 1E-3);

    svec vect = pq.vect();
    BOOST_CHECK_CLOSE(vect(0), 10, 1E-3);
    BOOST_CHECK_CLOSE(vect(1), 10, 1E-3);
}

BOOST_AUTO_TEST_CASE(intersection)
{
    point p1 = {0, 0};
    point q1 = {10, 10};
    Segment seg1(p1, q1);

    point p2 = {0, 10};
    point q2 = {10, 0};

    BOOST_CHECK(seg1.intersects(p2, q2));

    point ints = seg1.intersection(p2, q2);
    BOOST_CHECK_CLOSE(ints(0), 5, 1E-4);
    BOOST_CHECK_CLOSE(ints(1), 5, 1E-4);

}


// Tester.cpp : Defines the entry point for the console application.
//

#include <iostream>
#include <Eigen/Dense>
#include "Chapter3.h"

int DemoConsoleOutput();
int MatrixMultiplication();
int TransposeProperties();
int MultiplyingTransposedVectors();
int MatrixTransposedVectorMultiplication();
int InnerProduct();

int main()
{
	std::cout << "Linear Algebra: Concepts and Methods with Eigen" << std::endl;
	//MatrixMultiplication();
	//TransposeProperties();
	//MultiplyingTransposedVectors();
	//MatrixTransposedVectorMultiplication();
	//InnerProduct();
	Chapter3 chapter3;
	chapter3.IntroduceSelf();
	return 0;
}

int MatrixMultiplication()
{
	std::cout << "1.10: Matrix Multiplication" << std::endl;
	Eigen::MatrixXd matrix1(4, 3);
	matrix1(0, 0) = 1;
	matrix1(1, 0) = 2;
	matrix1(2, 0) = 1;
	matrix1(3, 0) = 2;

	matrix1(0, 1) = 1;
	matrix1(1, 1) = 0;
	matrix1(2, 1) = 2;
	matrix1(3, 1) = 2;

	matrix1(0, 2) = 1;
	matrix1(1, 2) = 1;
	matrix1(2, 2) = 4;
	matrix1(3, 2) = -1;

	std::cout << "Matrix 1:" << std::endl;
	std::cout << matrix1 << std::endl;

	Eigen::MatrixXd matrix2(3, 2);
	matrix2(0, 0) = 3;
	matrix2(1, 0) = 1;
	matrix2(2, 0) = -1;

	matrix2(0, 1) = 0;
	matrix2(1, 1) = 1;
	matrix2(2, 1) = 3;

	std::cout << "Matrix 2:" << std::endl;
	std::cout << matrix2 << std::endl;

	std::cout << "Matrix 1 * Matrix 2:" << std::endl;
	std::cout << matrix1 * matrix2 << std::endl;

	return 0;
}

int TransposeProperties()
{
	std::cout << "1.29: Transpose Properties" << std::endl;

	Eigen::Matrix2f matrix1;
	matrix1 << 1, 2, 6, 8;
	Eigen::Matrix2f matrix2;
	matrix2 << 3, 4, 10, 12;
	std::cout << "matrix1*matrix2 transpose" << std::endl;
	std::cout << (matrix1 * matrix2).transpose() << std::endl;
	std::cout << "should equal matrix2 transpose *matrix1 transpose" << std::endl;
	std::cout << matrix2.transpose() * matrix1.transpose() << std::endl;
	std::cout << "and should not equal matrix1 transpose * matrix2 transpose" << std::endl;
	std::cout << matrix1.transpose() * matrix2.transpose() << std::endl;

	return 0;
}

int MultiplyingTransposedVectors()
{
	std::cout << "1.33: Calculate aTb and abT" << std::endl;

	Eigen::Vector3d vectorA(1,2,3);
	Eigen::Vector3d vectorB(4, -2, 1);
	std::cout << "a transpose" << std::endl;
	std::cout << vectorA.transpose() << std::endl;
	std::cout << "times b" << std::endl;
	std::cout << vectorA.transpose() * vectorB<< std::endl;
	std::cout << "and b transpose * a" << std::endl;
	std::cout << vectorA * vectorB.transpose() << std::endl;

	return 0;
}

int MatrixTransposedVectorMultiplication()
{
	std::cout << "1.38: Vectors and matrices" << std::endl;

	Eigen::Vector3d vectorA(1, 2, 3);
	Eigen::Matrix3d matrixA;
	matrixA << 1, 1, 1,
		2, 2, 2,
		3, 3, 3;
	std::cout << "a transpose" << std::endl;
	std::cout << vectorA.transpose() << std::endl;
	std::cout << "times matrixA" << std::endl;
	std::cout << matrixA << std::endl;
	std::cout << "equals" << std::endl;
	std::cout << vectorA.transpose() * matrixA << std::endl;

	return 0;
}

int InnerProduct()
{
	std::cout << "1.92: Inner Product" << std::endl;

	Eigen::Vector2d a(1, 2);
	Eigen::Vector2d b(3, 1);
	auto t = a.transpose().dot(b.transpose());
	auto l_of_a = sqrt(a.transpose().dot(a.transpose()));
	auto l_of_b = sqrt(b.transpose().dot(b.transpose()));
	auto lp = l_of_a * l_of_b;
	auto ct = t / lp;

	std::cout << "law of cosines states the inner product off the transposes of (1,2) and (3,1) " << std::endl;
	std::cout << t << std::endl;
	std::cout << "divided by the product of the lengths of said matrices" << std::endl;
	std::cout << lp << std::endl;
	std::cout << ct << std::endl;
	std::cout << "is equal to the product of the square root of the inner product of each of said matrixes with themselves times cosine theta" << std::endl;
	std::cout << lp * ct << std::endl;

	return 0;
}

int DemoConsoleOutput()
{
	Eigen::MatrixXd matrix1(2, 2);
	matrix1(0, 0) = 3;
	matrix1(1, 0) = 2.5;
	matrix1(0, 1) = -1;
	matrix1(1, 1) = matrix1(1, 0) + matrix1(0, 1);
	std::cout << matrix1 << std::endl;

	std::cout << "This is a simple string literal" << std::endl;

	std::cout << "Pi when approximated is 22 / 7 = " << 22 / 7 << std::endl;

	std::cout << "Pi actually is 22 / 7 = " << 22.0 / 7 << std::endl;

	return 0;
}


#pragma once

// Include Eigen
#include <Eigen/Core>
#include <Eigen/LU>
#ifdef USE_SPARSE_EIGEN
#include <Eigen/Sparse>
typedef Eigen::SparseMatrix<float> MatrixType;
#else
typedef Eigen::MatrixXf MatrixType;
#endif

// Include STL
#include <cmath>
#include <vector>

// Local include
#include "AxialMoments.hpp"

/* _Zonal Weigths_
 *
 * Compute the matrix of weights w_{l,i} that converts dot powers (wd, w)^i
 * to a Zonal Hamonics. More precisely:
 *
 *     y_{l, 0}(w · wd) = ∑_i w_{l,i} (w · wd)^i, V l in [0 .. order]
 *
 */
inline Eigen::MatrixXf ZonalWeights(int order) {

   // W is the matrix of the weights. It is build recursively using the Legendre
   // polynomials. The trick here is that Legendre polynomials are simply the
   // shift in order of a previous pol. summed to another previous pol.
   Eigen::MatrixXf W = Eigen::MatrixXf::Zero(order, order);
   W(0,0) = 1.0f;
   W(1,1) = 1.0f;
   for(int n=2; n<order; ++n) {
      const int subsize = n;
      W.row(n).segment(1, subsize) = (2*n-1) * W.row(n-1).segment(0, subsize);
      W.row(n) -= (n-1) * W.row(n-2);
      W.row(n) /= n;
   }

   // Scale each columns by the corresponding √(2l+1 / 4π) factor.
   const float factor = 1.0f/sqrt(4.0f*M_PI);
   for(int n=0; n<W.rows(); ++n) {
      W.row(n) = W.row(n) * sqrt(2*n+1) * factor;
   }

   return W;
}

/* _Vector Group Zonal Weigths_
 *
 * TODO This matrix should do the mixing between the ordered power of cosines
 * vector and the shuffled vector of ZH coefficients.
 */
template<class Vector>
inline Eigen::MatrixXf ZonalWeights(const std::vector<Vector>& directions) {

   const int dsize = directions.size();
   const int order = (dsize-1) / 2 + 1;
   const int mrows = order*order;

   Eigen::MatrixXf result = Eigen::MatrixXf::Zero(mrows, dsize*order);

   const auto ZW = ZonalWeights(order);

   // Each vector fills a given set of column entries with decreasing
   // number to do the swapping. For example, the 0th vector will fill
   // entries from order 0 to max_order but the 1srt vector will fill
   // entries from 1 to max_order.
   for(int i=0; i<dsize; ++i) {
      for(int j=0; j<order; ++j) {
         if(i >= 2*j+1) {
            continue;
         }

         const int shift_rows = j*j + i;
         const int shift_cols = order*i;

         result.block(shift_rows, shift_cols, 1, order) = ZW.row(j);
      }
   }
   return result;
}

/* _Zonal Normalization_
 *
 * This little code compute the zonal normalization for spherical harmonics
 * basis using the √(2l+1 / 4π) factor. It can later by applied to a zonal
 * vector using Eigen fast product: a.cwiseProduct(b)
 */
inline Eigen::VectorXf ZonalNormalization(int order) {
   Eigen::VectorXf res = Eigen::VectorXf(order);
   const float f = 1.0f/sqrt(4.0f*M_PI);
   for(int i=0; i<order; ++i) {
      res[i] = sqrt(2*i+1)*f;
   }
   return res;
}

/* _Rotated ZH_
 *
 * Evaluate the rotated ZH, with respect to principal direction `d` in
 * direction `w` for order in [0..order].
 *
 *   z_i = P_i( d · w ),  where P_i is Legendre polynomial
 */
template<class Vector>
inline Eigen::VectorXf RotatedZH(const Vector& d, const Vector& w, int order) {

   Eigen::VectorXf res = Eigen::VectorXf::Zero(order);
   const float z = Vector::Dot(d, w);

   res[0] = 1.0f;
   if(order == 1) {
      return res /sqrt(4.0f*M_PI);
   }

   res[1] = z;
   if(order == 2) {
      res[1] *= sqrt(3.0f);
      return res / sqrt(4.0f*M_PI);
   }

   // Using Bonnet recurrence formula
   for(int i=2; i<order; ++i) {
      const int i2 = i-1;
      res[i]  = (2*(i2)+1)*z*res[i2] - (i2)*res[i-2];
      res[i] /= i;
   }

   // Apply zonal weights
   const auto f = ZonalNormalization(order);
   res = res.cwiseProduct(f);
   return res;
}

/* _ZH Fast Evaluation_
 *
 * Evaluate the Zonal Harmonics vector for all `directions` while respecting
 * a lobe sharing order. This means that the output vector will be composed as:
 *
 *     v = [ z_{0,0}, z_{1,0}, z_{1,1}, z_{1,2}, ...]
 *
 * where z_{i,j} = Ylm_{i, 0}(w_j).
 */
template<class Vector>
inline Eigen::VectorXf ZHEvalFast(const std::vector<Vector>& dirs, const Vector& w) {

   // Get the number of elements to compute
   const int dsize = dirs.size();
   const int order = (dsize-1) / 2 + 1;
   const int vsize = order*order;

   Eigen::VectorXf v(vsize);

   // The loop is first over the order term then over the set of directions
   // starting from the 0 index that is reused for all bands.
   float ylm = 0.0;
   for(int i=0; i<dsize; ++i) {

      const Vector& n   = dirs[i];
      const auto    ylm = RotatedZH<Vector>(n, w, order);

      for(int l=0; l<order; ++l) {
         if(i >= 2*l+1) {
            continue;
         }
         v[l*l + i] = ylm[l];
      }
   }

   return v;
}

/* _Zonal Expansion_
 *
 * Expands a Spherical Harmonics vector into a Zonal Harmonics matrix transform.
 * Each band of spherical harmonics is decomposed into a set of Zonal Hamonics
 * with specific directions `directions`.
 *
 * The conversion matrix A is computed as the inverse of the evaluation of the
 * SH basis a the particular directions.
 *
 * The vector of directions must be of size `2*order+1`, where `order` is the
 * max order of the SH expansion.
 *
 * The template class SH must permit to access its basis elements, the y_{l,m}
 * as the static function `SH::FastBasis(const Vector& w, int order)`.
 */
template<class SH, class Vector>
inline MatrixType ZonalExpansion(const std::vector<Vector>& directions) {

   // Get the current band. Here I use a shifted order number. The integer
   // order is actually `order+1` to compute the number of rows and iterate
   // over it. Later in the code I evaluate the correct order to get the
   // ylm from SH::FastBasis.
   const int dsize = directions.size();
   const int order = (dsize-1) / 2 + 1;
   const int mrows = order*order;
   assert(order >= 0);

   const auto zhNorm = ZonalNormalization(order);

#ifdef USE_SPARSE_EIGEN
   MatrixType Y(mrows, mrows);
   std::vector<Eigen::Triplet<float>> triplets;
#else
   MatrixType Y = Eigen::MatrixXf::Zero(mrows, mrows);
#endif
   for(int i=0; i<dsize; ++i) {

      // Get the vector associated to the current row
      const Vector& w = directions[i];

      // Evaluate all the Y_{l,m} for the current vector
      auto ylm = SH::FastBasis(w, order-1);

      // Complete all the submatrices starting from column `i` using order `j`
      // size for the ZH element.
      for(int j=0; j<order; ++j) {
         if(i >= 2*j+1) {
            continue;
         }

         const int  shift = j*j;
         const int  vsize = 2*j+1;
#ifdef USE_SPARSE_EIGEN
         for(int k=0; k<vsize; ++k) {
            const float& v = ylm[shift+k];
            triplets.push_back(Eigen::Triplet<float>(shift+i, shift+k, v));
         }
         Y.setFromTriplets(triplets.begin(), triplets.end());
#else
         Y.block(shift+i, shift, 1, vsize) = ylm.segment(shift, vsize).transpose() / zhNorm[j];
#endif
      }
   }

   return Y;
}

/* _Compute the Inverse of Matrix Y_
 *
 * Since the matrix resulting from ZonalExpansion is block diagonal, its
 * inverse is trivial to compute. We must simply take the inverse of each
 * block, in place.
 *
 * TODO: Make the sparse version.
 */
inline MatrixType computeInverse(const MatrixType& Y) {
   const int nrows = Y.rows();
   const int order = sqrt(nrows);

#ifdef USE_SPARSE_EIGEN
   MatrixType A(mrows, nrows);
   std::vector<Eigen::Triplet<float>> triplets;
#else
   MatrixType A = Eigen::MatrixXf::Zero(nrows, nrows);
#endif

   for(int j=0; j<order; ++j) {
      const int shift = j*j;
      const int size  = 2*j+1;

#ifdef USE_SPARSE_EIGEN
      assert(false);
#else
      const auto& block = Y.block(shift, shift, size, size);

      // Check if the block is Zero or not in debug mode
      if(block.isZero()) {
         std::cout << "Block of order " << j << " is zero" << std::endl;
         std::cout << block << std::endl << std::endl;
      }
      //assert(!block.isZero());

      A.block(shift, shift, size, size) = block.inverse();
#endif
   }
   return A;
}

/* _Compute the SH Integral over a Spherial Triangle_
 *
 * This function is provided as an example of how to use the different
 * components of this package. It is probably much faster to precompute the
 * product `Prod` of the ZonalWeights and the Zonal to SH conversion matrix.
 */
template<class Triangle, class Vector, class SH>
inline float computeSHIntegral(const Eigen::VectorXf& clm,
                               const std::vector<Vector>& basis,
                               const Triangle& triangle) {

   // Get the Zonal weights matrix and the Zlm -> Ylm conversion matrix
   // and compute the product of the two: `Prod = A x Zw`.
   const auto ZW = ZonalWeights<Vector>(basis);
   const auto Y  = ZonalExpansion<SH, Vector>(basis);
   const auto A  = computeInverse(Y);

   const auto Prod = A*ZW;

   // Analytical evaluation of the integral of power of cosines for
   // the different basis elements up to the order defined by the
   // number of elements in the basis
   const auto moments = AxialMoments<Triangle, Vector>(triangle, basis);

   return clm.dot(Prod * moments);
}

#ifdef LATER
/* _Compute the SH Integral over a Spherial Triangle_
 *
 * This function is provided as an example of how to use the different
 * components of this package. It is probably much faster to precompute the
 * product `Prod` of the ZonalWeights and the Zonal to SH conversion matrix.
 */
template<class Triangle, class Vector, class SH>
inline float computeSHIntegral(const Eigen::VectorXf& clm,
                               const Triangle& triangle) {

   // Get the order of the provided SH vector and compute the directional
   // sampling of the sphere for rotated ZH/cosines.
   const auto order = sqrt(clm.size())-1;
   const auto basis = SamplingFibonacci<Vector>(2*order+1);

   // Get the Zonal weights matrix and the Zlm -> Ylm conversion matrix
   // and compute the product of the two: `Prod = A x Zw`.
   const auto ZW = ZonalWeights<Vector>(basis);
   const auto Y  = ZonalExpansion<SH, Vector>(basis);
   const auto A  = computeInverse(Y);

   const auto Prod = A*ZW;

   // Analytical evaluation of the integral of power of cosines for
   // the different basis elements up to the order defined by the
   // number of elements in the basis
   const auto moments = AxialMoments<Triangle, Vector>(triangle, basis);

   return clm.dot(Prod * moments);
}
#endif


//
// Created by James Koh on 03/02/2021.
//

#include <iostream>
#include <Eigen/Dense>

namespace DM {
    using namespace Eigen;

    MatrixXd Direction(VectorXd jacobian, MatrixXd hessian_inverse) {
        return - hessian_inverse * jacobian;
    }

    double LambdaSquared(VectorXd jacobian, MatrixXd hessian_inverse) {
        return jacobian.transpose() * hessian_inverse * jacobian;
    }

    VectorXd LineSearchUpdate(VectorXd x, VectorXd delta_x, double alpha, double beta,
                              double F (VectorXd), VectorXd jacobian) {
        double t = 1.0;

        while (F(x + t * delta_x) > (F(x) + jacobian.dot(delta_x) * (alpha * t))) {
            t = beta * t;
        }

        return x + t * delta_x;
    }

    VectorXd Newton(VectorXd x0, double epsilon, double alpha, double beta,
                    double F (VectorXd), VectorXd J (VectorXd), MatrixXd H (VectorXd)) {
        VectorXd x = x0;
        int i = 1;

        while (true) {
            std::cout << "Iteration " << i << ":" << std::endl;

            VectorXd jacobian = J(x);
            MatrixXd hessian = H(x);
            MatrixXd hessian_inverse = H(x).inverse();

            VectorXd delta_x = Direction(jacobian, hessian_inverse);
            double lambda_squared = LambdaSquared(jacobian, hessian_inverse);

            std::cout << "Lambda^2: " << lambda_squared << std::endl;

            if (lambda_squared / 2 < epsilon || i > 100)
                break;

            x = LineSearchUpdate(x, delta_x, alpha, beta, F, jacobian);
            std::cout << "Solution :" << F(x) << std::endl;

            i++;
        }

        return x;
    }
}


#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int main()
{
  Eigen::MatrixXf m(2,2);

  m << 1, 2,
       3, 4;

  //get location of maximum
  MatrixXf::Index maxRow, maxCol;
  float max = m.maxCoeff(&maxRow, &maxCol);

  //get location of minimum
  MatrixXf::Index minRow, minCol;
  float min = m.minCoeff(&minRow, &minCol);

  cout << "Max: " << max <<  ", at: " <<
     maxRow << "," << maxCol << endl;
  cout << "Min: " << min << ", at: " <<
     minRow << "," << minCol << endl;
}


#include "writer.hpp"
#include <Eigen/Sparse>
#include <Eigen/SparseCholesky>
#include <cmath>
#include <iostream>
#include <stdexcept>

//! Sparse Matrix type. Makes using this type easier.
typedef Eigen::SparseMatrix<double> SparseMatrix;

//! Used for filling the sparse matrix.
typedef Eigen::Triplet<double> Triplet;

//! Vector type
typedef Eigen::VectorXd Vector;

//! Our function pointer, typedef'd to make it easier to use
typedef double (*FunctionPointer)(double);

//! Create the Stiffness matrix for 1D with boundary terms
//! @param[out] A will be the Galerkin matrix (as in the exercise)
//! @param[in] N as in the exercise
//! @param[in] dx the cell length
void createStiffnessMatrixWithBoundary(SparseMatrix &A, int N, double dx) {
	std::vector<Triplet> triplets;
	A.resize(N + 2, N + 2);

	// Reserve the space we will allocate
	triplets.reserve((N + 2) + 2 * N + 2);

	// (write your solution here)
	A.setZero();
	for (int i = 0; i < N + 2; i++) {
		triplets.push_back(Triplet(i, i, 2 / dx));
		if (i >= 1) {
			triplets.push_back(Triplet(i, i - 1, -1 / dx));
		}
		if (i <= N + 1) {
			triplets.push_back(Triplet(i, i + 1, -1 / dx));
		}
	}
	A.setFromTriplets(triplets.begin(), triplets.end());
}

//! Creates the right hand side for the finite element method in the exericse
//! @param[out] rhs the resulting right hand side (or phi in the exercise)
//! @param[in] f the function pointer to f
//! @param[in] dx the cell length
//! @param[in] x the x points
void createRHS(Vector &rhs, FunctionPointer f, int N, double dx, const Vector &x) {
	rhs.resize(N + 2);

	// (write your solution here)
	rhs(0) = dx / 2 * f(x(0));
	for (int i = 1; i < N + 1; i++) {
		rhs(i) = dx * f(x(i));
	}
	rhs(N + 1) = dx / 2 * f(x(N + 1));
}

//! Solve the equation
//!
//!    $-u''(x) = f(x)$
//!
//! using FEM on the interval $[a,b]$.
//!
//! @param[out] u at the end, will have all the values of u
//! @param[out] x will be the x points
//! @param[in] f should be a pointer to the function f
//! @param[in] N number of inner cells to use
//! @param[in] a endpoint on left side
//! @param[in] b endpoint on right side
//! @param[in] ua boundary value at a
//! @param[in] ub boundary value at b
void femSolve(Vector &u, Vector &x, FunctionPointer f, int N, double a, double b, double ua = 0.0, double ub = 0.0) {
	double dx = (b - a) / (N + 1);

	// Fill x vector
	x.setLinSpaced(N + 2, a, b);

	SparseMatrix A;
	createStiffnessMatrixWithBoundary(A, N, dx);

	Vector phi;
	createRHS(phi, f, N, dx, x);

	// (write your solution here)

	u.resize((N + 2));
	u.setZero();

	// Do boundary conditions
	// (write your solution here)
	u(0)     = ua;
	u(N + 1) = ub;
	phi -= A * u;

	//solve inner system
	// (write your solution here)
	SparseMatrix innerA = A.block(1, 1, N, N);

	Eigen::SparseLU<SparseMatrix> solver;
	solver.compute(innerA);
	if (solver.info() != Eigen::Success) {
		throw std::runtime_error("Could not decompose the matrix.");
	}
	u.segment(1, N) = solver.solve(phi.segment(1, N));
}

void computeWithoutBoundaryValues() {
	Vector u;
	Vector x;
	femSolve(u, x, std::sin, 100, -M_PI, M_PI);

	writeToFile("u_wo_bc_fem.txt", u);
	writeToFile("x_wo_bc_fem.txt", x);
}

void computeWithBoundaryValues() {
	Vector u;
	Vector x;
	femSolve(u, x, std::cos, 100, -M_PI, M_PI, -1.0, 1.0 / 2.0);

	writeToFile("u_w_bc_fem.txt", u);
	writeToFile("x_w_bc_fem.txt", x);
}

int main(int, char **) {
	computeWithoutBoundaryValues();
	computeWithBoundaryValues();
}


#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

int main()
{
  MatrixXd m(2,5);
  m.resize(4,3);
  std::cout << "The matrix m is of size "
            << m.rows() << "x" << m.cols() << std::endl;
  std::cout << "It has " << m.size() << " coefficients" << std::endl;
  VectorXd v(2);
  v.resize(5);
  std::cout << "The vector v is of size " << v.size() << std::endl;
  std::cout << "As a matrix, v is of size "
            << v.rows() << "x" << v.cols() << std::endl;
}


#include <iostream>
#include <chrono>

#include <Eigen/Core>  // Eigen 核心部分
#include <Eigen/Dense>  // 稠密矩阵的代数运算（逆，特征值等）
#include <Eigen/Geometry>  // Eigen/Geometry 模块提供了各种旋转和平移的表示

#include <opencv2/opencv.hpp>

int main(int argc, char **argv){

    double a_e = 2.0, b_e = -1.0, c_e = 5.0;  // 待拟合参数 及估计初值
    double a = 1.0, b = 2.0, c = 1.0;  // 待拟合参数 实际值
    cv::RNG rng;  // OpenCV 随机数产生器
    double w_sigma = 1.0;
    double inv_sigma = 1.0 / w_sigma;

    // 生成数据
    int num_data = 100;
    std::vector<double> t_data, y_data;

    for(int i = 0; i < num_data; i++){
        double t = i / 100.0;
        double y = exp(a*t*t + b*t + c) + rng.gaussian(w_sigma * w_sigma);
        t_data.push_back(t);
        y_data.push_back(y);
    }

    std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
    // 迭代-优化
    Eigen::Vector3d x(a_e, b_e, c_e);
    int num_iters = 20;
    double cost = 0, lastCost = 0;

    for(int iter = 0; iter < num_iters; iter++){
        Eigen::Matrix3d H = Eigen::Matrix3d::Zero();
        Eigen::Vector3d g = Eigen::Vector3d::Zero();
        cost = 0;
        for (int i = 0; i < num_data; i++){
            double t = t_data[i];
            double y = y_data[i];
            double y_e = exp(x[0]*t*t + x[1]*t + x[2]);

            double error = y_e - y;
            Eigen::Matrix<double, 1, 3> J;
            J[0] = t * t * exp(x[0]*t*t + x[1]*t + x[2]);
            J[1] = t * exp(x[0]*t*t + x[1]*t + x[2]);
            J[2] = exp(x[0]*t*t + x[1]*t + x[2]);

            H += inv_sigma * inv_sigma * J.transpose() * J;
            g += - inv_sigma * inv_sigma * J * error;
            cost += error * error;
        }

        if (iter >= 1 && cost >= lastCost){
            std::cout << "cost >= lastCost, break." << std::endl;
            break;
        }
        lastCost = cost;

        Eigen::Vector3d dx = H.ldlt().solve(g);
        if (dx.norm() < 1e-6){
            std::cout << "||dx|| < 1e-6, break." << std::endl;
            break;
        }
        x += dx;

        std::cout << "iter = " << iter << " , estimated parameters = " << x.transpose()
                  << " , cost = " << cost << std::endl;
    }

    std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now();
    std::chrono::duration<double> time_used = std::chrono::duration_cast <std::chrono::duration<double>> (t2 - t1);

    std::cout << "final , estimated parameters = " << x.transpose()
                  << " , cost = " << cost << std::endl;
    std::cout << "time_cost = " << time_used.count() << "second" << std::endl;

    return 0;
}


/**
 * Reference: The code is copied from:
 * https://eigen.tuXdamily.org/dox/classEigen_1_1JacobiSVD.html
 */

#include <Eigen/Core>
#include <Eigen/Geometry>
// #include <Eigen/Dense> // For initializing MatrixXd
#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
     // Eigen::MatrixXd mat = Eigen::MatrixXd::Random(3, 2);
     // Eigen::MatrixXd mat = Eigen::MatrixXd::Zero(3, 2);
     // Eigen::Matrix3d mat = Eigen::Matrix3d::Zero();
     Eigen::MatrixXd mat(2, 2);
     mat(0, 0) = 1.0;
     mat(1, 0) = 1.0;
     mat(0, 1) = 5.0;
     mat(1, 1) = 5.0;

     cout << "Here is the matrix mat:" << endl
          << mat << endl;

     Eigen::JacobiSVD<Eigen::MatrixXd> svd(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
     Eigen::Vector2d s = svd.singularValues();
     Eigen::Matrix<double, 2, 2> u = svd.matrixU();
     Eigen::Matrix<double, 2, 2> v = svd.matrixV();
     cout << "Its singular values are:" << endl
          << svd.singularValues() << endl;
     cout << "Its left singular vectors are the columns of the thin U matrix:" << endl
          << svd.matrixU() << endl;
     cout << "Its right singular vectors are the columns of the thin V matrix:" << endl
          << svd.matrixV() << endl;

     // Eigen::Vector3d rhs(1, 0, 0);
     Eigen::Vector2d rhs(1, 0);
     cout << "Now consider this rhs vector:" << endl
          << rhs << endl;
     cout << "A least-squares solution of mat*x = rhs is:" << endl
          << svd.solve(rhs) << endl;

     Eigen::Vector2d mean = mat.colwise().mean();     // 1, 5
     Eigen::Vector2d mean_row = mat.rowwise().mean(); // 3, 3
     typedef Eigen::Matrix<double, 1, 2> Mat12d;
     Mat12d mean_col = mat.colwise().mean(); // 1, 5

     cout << "Column wise mean: " << mean << endl;
     cout << "Row wise mean: " << mean_row << endl;
     cout << "Subtraction by colwise(): " << mat.colwise() - mean << endl;
     cout << "Subtraction by rowwise(): " << mat.rowwise() - mean.transpose() << endl;

     Eigen::Vector2d first_column = mat.col(0);
     cout << "\n first_column: " << first_column << endl;
     double norm_of_first_column = first_column.dot(first_column);
     cout << "\n norm_of_first_column: " << norm_of_first_column << endl;

     return 0;
}


#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/SparseLU>
#include <vector>
#include <iomanip>

#include "errors.hpp"

using namespace Eigen;

int main() {

    // Construct data for RK order 4
    MatrixXd A = MatrixXd::Zero(4,4);
    A(1,0) = .5;
    A(2,1) = .5;
    A(3,2) = 1;
    VectorXd b(4);
    b << 1./6, 1./3, 1./3, 1./6;

    // Construct data for the IVP
    double T = 1;
    int n = 5;
    VectorXd y0(2*n);
    for(int i = 0; i < n; ++i) {
        y0(i)=(i+1.)/n;
        y0(i+n)=-1;
    }

    auto f = [n] (VectorXd y) {
        VectorXd fy(2*n);

        VectorXd g(n);
        g(0) = y(0)*(y(1)+y(0));
        g(n-1) = y(n-1)*(y(n-1)+y(n-2));
        for(int i = 1; i < n-1; ++i) {
            g(i) = y(i)*(y(i-1)+y(i+1));
        }

        Eigen::SparseMatrix<double> C(n,n);
        C.reserve(3);
        for(int i = 0; i < n; ++i) {
            C.insert(i,i) = 2;
            if(i < n-1) C.insert(i,i+1) = -1;
            if(i >= 1)  C.insert(i,i-1) = -1;
        }
        C.makeCompressed();
        fy.head(n) = y.head(n);

        Eigen::SparseLU< Eigen::SparseMatrix<double> >  solver;
        solver.analyzePattern(C);
        solver.compute(C);
        fy.tail(n) = solver.solve(g);
        return fy;
    };

    errors(f, T, y0, A, b);
}

Nummerical Methods for CSE/PS12/solutions_ps12/system.cpp


#include <Eigen/Core>
#include <Eigen/QR>
#include <iostream>
using namespace Eigen;

void func1(void) {
  MatrixXd A = MatrixXd::Random(5, 8);
  VectorXd b = VectorXd::Random(5);
  VectorXd b0 = b; //save b because we are going to write over during computations  // You should have already done something like this.
  ColPivHouseholderQR<MatrixXd> qr(A.transpose());
  MatrixXd Q = qr.matrixQ();  // This computes A^+ * b
  auto R = qr.matrixQR().topRows(5).transpose().template triangularView<Lower>();
  b = qr.colsPermutation().transpose()* b;
  R.solveInPlace(b);
  VectorXd x = Q.leftCols(5) * b;  // just checking the result
  std::cout << "x = " << x.transpose() << std::endl;
  std::cout << "||A*x-b0|| = " << (A * x - b0).norm() << std::endl;  // for comparison, the solve of CompleteOrthogonalDecomposition does a pseudo-inverse
  MatrixXd pinvA = A.completeOrthogonalDecomposition().pseudoInverse();
  VectorXd x0 = pinvA * b0;  std::cout << "x0 = " << x0.transpose() << std::endl;
  std::cout << "||A*x0-b0|| = " << (A * x0 - b0).norm() << std::endl;
  std::cout << "||x - x0|| = " << (x0 - x).norm() << std::endl;
}

void func2(void) {
  using namespace std;
  MatrixXd A = MatrixXd::Random(5, 8);
  VectorXd b = VectorXd::Random(5);
  VectorXd b0 = b; //save b because we are going to write over during computations  // You should have already done something like this.
  ColPivHouseholderQR<MatrixXd> qr(A.transpose());
  MatrixXd Q = qr.matrixQ();  // This computes A^+ * b
  MatrixXd R = qr.matrixR();
  MatrixXd P = qr.colsPermutation();
  double rank = qr.rank();

  MatrixXd R_upper = R.topRows(rank);
  auto RT = R_upper.transpose().template triangularView<Lower>();
  MatrixXd PT = P.transpose();
  RT.solveInPlace(PT);
  cout << "A * (Q*R^(-T)*P^T)" << endl;
  cout << A*(Q.leftCols(rank)*PT) << endl;

  MatrixXd pinvA = A.completeOrthogonalDecomposition().pseudoInverse();
  VectorXd x0 = pinvA * b0;
  cout << "Psuedo Inverse A : " << endl;
  cout << pinvA << endl;
  cout << "(Q*R^(-T)*P^T) : " << endl;
  cout << Q.leftCols(rank)*PT << endl;
}

int main()
{
  func1();
  func2();
}


// { Driver Code Starts
//Initial template for C++

#include <boost/multiprecision/cpp_int.hpp>
using boost::multiprecision::cpp_int;  // https://www.geeksforgeeks.org/factorial-large-number-using-boost-multiprecision-library/
using namespace std;

 // } Driver Code Ends
//User function template for C++

class Solution
{
    public:

    // Catalan series:  1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, …
    // Formulae to get the series: C0 = 0, C(N+1) = sum0ToN(Ci*C(N-i))

    //Function to find the nth catalan number.

    cpp_int nthCatalan(int n){
       vector<cpp_int> dp(n+1,0);

       for(int i=0;i<n+1;i++){
           if(i==0 or i==1) dp[i] = 1;
           else{
               for(int j=0;j<i;j++)
                   dp[i] += dp[j]*dp[i-j-1];
           }
       }
       return dp[n];
    }

    cpp_int findCatalan(int n)
    {
        //code here
        cpp_int ans = nthCatalan(n);
        return ans;
    }
};

// { Driver Code Starts.

int main()
{
    //taking count of testcases
	int t;
	cin>>t;
	while(t--) {

	    //taking nth number
	    int n;
	    cin>>n;
	    Solution obj;
	    //calling function findCatalan function
	    cout<< obj.findCatalan(n) <<"\n";
	}
	return 0;
}  // } Driver Code Ends


#include <iostream>
#include <ctime>
using namespace std;

//#include <Eigen/Core>
#include <Eigen/SVD>
//#include <Eigen/Dense>
// 稠密矩阵的代数运算 逆矩阵，特征值
#include "/usr/include/eigen3/Eigen/Dense"
#include "/usr/include/eigen3/Eigen/Core"

#define MATRIX_SIZE (50)

int main(int argc, char **argv){

	Eigen::Matrix<float,2,3> matrix_23;
	/* Vertor3D is double 3,1, 三维坐标就相当于矩阵中1行3列 */
	Eigen::Vector3d v_3d;
	/* matrxi3d is doule 3,3 */
//	Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero();
	/* 特殊类型 */
	Eigen::MatrixXd matrix_x;

	matrix_23 << 1,1,2,2,5,5;
	cout << matrix_23 <<endl;
	cout << matrix_23.cols() << endl;

	for (int i = 0; i < matrix_23.rows(); i++)
		for(int j = 0;j < matrix_23.cols(); j++)
				cout << matrix_23(i,j) << " ";
	v_3d << 1, 2, 3;
	cout << endl <<  "-- " << v_3d.transpose() << endl;

//	Eigen::Matrix<double,2,3> wrong_type = matrix_23;
//	Eigen::Matrix<double,2,3> cast_type = matrix_23.cast<double>();
	Eigen::Matrix<double,2,1> cast_type = matrix_23.cast<double>() * v_3d;
	cout << cast_type << endl;

	/* 四则运算 */
	Eigen::Matrix3d matrix_3d = Eigen::Matrix3d::Random();
	matrix_3d << 1,2,0,0,2,3,1,0,3;
	cout << "---------------" << endl << matrix_3d << endl;

	cout << "-------transpose--------" << endl << matrix_3d.transpose() << endl;
	cout << "-------sum--------" << endl << matrix_3d.sum() << endl;
	cout << "-------trace--------" << endl << matrix_3d.trace() << endl;
	cout << "-------multiple--------" << endl << matrix_3d*96 << endl;
	cout << "-------inverse--------" << endl << matrix_3d.inverse() << endl;
	cout << "-------[ 1 ]--------" << endl << matrix_3d.inverse()*matrix_3d << endl;
	cout << "-------determinant------" << endl << matrix_3d.determinant() << endl;

	matrix_3d = Eigen::Matrix3d::Random();
	cout << "-------eigen random:" << endl << matrix_3d << endl;
	Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver(matrix_3d.transpose()*matrix_3d);
	cout << "-------eigen tra*mat:" << endl << matrix_3d.transpose()*matrix_3d << endl;
	cout << "-------eigen values:" << endl << solver.eigenvalues() << endl;
	cout << "-------eigen vector" << endl << solver.eigenvectors() << endl;
//	Eigen::Matrix<double, MATRIX_SIZE, MATRIX_SIZE> Matrix_MM = Eigen::Matrix<double,MATRIX_SIZE,MATRIX_SIZE>::Random(); //eigen default size is 50
	//Eigen::Matrix<double, 50,50> Matrix_MM = Eigen::Matrix<double,50,50>::Random(); //eigen default size is 50
	//Eigen::Matrix<double, MATRIX_SIZE, 1> v_M = Eigen::Matrix<double,MATRIX_SIZE,1>::Random();
	//cout << "-------Matrix_MM:" << endl << Matrix_MM << endl;
	/* 求逆 */
	clock_t time_st = clock();
//	cout << "-------Result:" << endl << Matrix_MM.inverse()*v_M << endl;
//	cout << "-------Timest:" << endl << 1000*(clock()-time_st)/(double)CLOCKS_PER_SEC <<endl;
//
//	time_st = clock();
//	cout << "-------Result:" << endl << Matrix_MM.colPivHouseholderQr().solve(v_M) << endl;
//	cout << "-------Result:" << endl << Matrix_MM.fullPivHouseholderQr().solve(v_M) << endl;
//	cout << "-------Timest:" << endl << 1000*(clock()-time_st)/(double)CLOCKS_PER_SEC <<endl;
//	/* 速度没有变快，反而变慢，不懂为何。8ms , 12.1ms*/

	/* 100*100的随机矩阵 */
	Eigen::Matrix<double, 100, 1> v_D = Eigen::Matrix<double,100,1>::Random();
	//Eigen::Matrix< double,Eigen::Dynamic,Eigen::Dynamic> matrix_dynamic;
	Eigen::Matrix< double, 100, 100> matrix_dynamic;
	matrix_dynamic = Eigen::Matrix<double,100,100>::Random();
	time_st = clock();
	cout << "-------Result:" << endl << matrix_dynamic.colPivHouseholderQr().solve(v_D).transpose() << endl;
	cout << "-------Timest:" << endl << 1000*(clock()-time_st)/(double)CLOCKS_PER_SEC <<endl;

	time_st = clock();
	cout << "-------Result:" << endl << matrix_dynamic.ldlt().solve(v_D).transpose() << endl;
	cout << "-------Timest:" << endl << 1000*(clock()-time_st)/(double)CLOCKS_PER_SEC <<endl;

	return 0;
}