#include <iostream>
#include <array>
#include <cmath>
#include <tuple>
#include <cassert>
#include <NTL/ZZ.h>
#include <NTL/vector.h>
#include <random>
#include <chrono>

using namespace std;

using namespace NTL;

//ex. compile:
//g++ -o <exe> remainder_alg_first_pass.cpp -std=c++11 -march=native -O2 -lntl -lgmp -lgmpxx -pthread

// to compile and run on linux use
// g++ -o <executable file name> remainder_alg_first_pass.cpp
// ./<executable file name>

//note that everywhere it says 'int' we will eventually want to use GMP or whatnot
//ints are too small...

//translates indices in trees to indices in arrays
//if you want left child of (i,j), do (i+1, 2*j)
//right child is (i+1, 2*j+1), and parent is (i-1, j//2)
int flatten_index(int i, int j)
{
	assert (j <= pow(2,i) - 1);
	return pow(2,i) +j-1;
}

//gives tree indices from array index
tuple<int, int> lift_index(int k)
{
	int i = log2(k+1);
	int j = k + 1 - pow(2,i);

	return make_tuple(i,j);
}

void print_tree(Vec<ZZ> & X)
{
	cout << endl;
	for (int i = 0; i < X.length(); i++)
	{
		cout << X[i] << " , ";
	}
	cout << endl;
}

//reflects a tree on the y-axis in place
void reflect_tree(Vec<ZZ> & X) //why doesn't mutability work the way I think it does?
{
	int depth = log2(X.length());

	for (int i = 1; i <= depth; i++)
	{
		int width = pow(2,i);

		for (int j = 0; 2*j < width; j++)
		{
			int a = flatten_index(i,j);
			int b = flatten_index(i, width-j-1);

			//this switches the two locations
			X[b] = X[a]^X[b];
			X[a] = X[a]^X[b];
			X[b] = X[a]^X[b];
		}
	}
}

Vec<ZZ> zero_vector(int N)
{
	Vec<ZZ> ret;
	ret.SetLength(N);
	for (int i = 0; i < N; i++)
	{
		ret[i] = 0;
	}

	return ret;
}

//given an array of size N, returns the product tree of size 2N
//assumes N is a power of 2
//it won't have to be (we can pad it etc.) but this is just a preliminary version
Vec<ZZ> product_tree(Vec<ZZ> &X, Vec<ZZ> &mtree)
{

	//INPUT: a list of integers; OUTPUT: a product tree of double the size
	int depth = log2(X.length()); //round this UP when not power of 2

	Vec<ZZ> ptree;
	ptree = zero_vector(2*X.length()-1);

	//initialize leaves
	for (int j = 0; j < pow(2, depth); j++)
	{
		int leaf = flatten_index(depth,j);

		ptree[leaf] = X[j];

		if (mtree[leaf] != 0)
		{
			ptree[leaf] %= mtree[leaf];
		}
	}

	//build up the product tree recursively
	for (int i = depth-1; i >= 0; i--)
	{
		for (int j = 0; j < pow(2,i); j++)
		{
			int parent = flatten_index(i,j);
			int left = 2*parent + 1;
			int right = left + 1;

			//padding is not necessary if on this step we catch IndexError with 1
			ptree[parent] = ptree[left]*ptree[right];

			if (mtree[parent] != 0)
			{
				ptree[parent] %= mtree[parent];
			}

		}
	}

	return ptree;
}

Vec<ZZ> accumulating_tree(Vec<ZZ> &X, Vec<ZZ> &mtree)
{
	//code cut from body of accumulating_remainder_tree
	//this can be used to store the product tree of A modulo the mi
	//this can be applied to any tree; for our applications we will only apply it to product trees
	//INPUT: a tree; OUTPUT: accumulating tree (of same size)
	assert (X.length() == mtree.length());

	int depth = log2(X.length());

	Vec<ZZ> acctree;
	acctree.SetLength(X.length());
	acctree[0] = 1;

	for (int i = 0; i < depth; i++)
	{
		for (int j = 0; j < pow(2,i); j++)
		{
			int parent = flatten_index(i,j);
			int left = 2*parent + 1;
			int right = left+1;

			acctree[left] = acctree[parent];
			acctree[right] = acctree[parent]*X[left];

			if (mtree[left] != 0)
			{
				acctree[left] %= mtree[left];
			}

			if (mtree[right] != 0)
			{
				acctree[right] %= mtree[right];
			}
		}
	}

	return acctree;

}

//so might make sense to pad beginning of m with a 1, and pad end of A with a 1
//given A0, A1, ... An, and m0, m1, ... mn, this returns
//1, A0 mod m1, A0*A1 mod m2, ... A0*...An-1 mod mn
Vec<ZZ> accumulating_remainder_tree(Vec<ZZ> &A, Vec<ZZ> &m)
{
	assert (A.length() == m.length());

	int depth = log2(A.length());

	Vec<ZZ> ztree = zero_vector(2*m.length()-1);

	Vec<ZZ> m_ptree = product_tree(m, ztree);

	//print_tree(m_ptree);
	reflect_tree(m_ptree);
	Vec<ZZ> m_acctree = accumulating_tree(m_ptree, ztree);
	reflect_tree(m_acctree);
	reflect_tree(m_ptree);

	//Vec<ZZ> m_acctree = reflect_tree(accumulating_tree(reflect_tree(m_ptree), ztree));

	//print_tree(m_acctree);

	//this power tree is reduced modulo the reflected m_ftree
	Vec<ZZ> A_ptree = product_tree(A, m_acctree);
	//delete m_acctree;

	//print_tree(A_ptree);

	Vec<ZZ> A_rtree = accumulating_tree(A_ptree, m_ptree);

	//print_tree(A_rtree);

	//need a nice array slice here...
	Vec<ZZ> C;
	C.SetLength(A.length());

	for (int j = 0; j < pow(2,depth); j++)
	{
		C[j] = A_rtree[flatten_index(depth, j)];
	}

	return C;

}

int main()
{
	long N = pow(2,16);

	Vec<ZZ> A;
	Vec<ZZ> m;

	A.SetLength(N);
	m.SetLength(N);

	random_device rd;
	mt19937 mt(rd());
	uniform_int_distribution<int> dist(1, N);

	for(int i = 0; i < N; i++){
		int bitsize = log2(i+1)+2;

		A[i] = dist(mt);
		m[i] = dist(mt);

	}

	//Vec<ZZ> ztree = zero_vector(2*N);

	//print_tree(A);
	//print_tree(m);

	auto start = chrono::high_resolution_clock::now();
	Vec<ZZ> remainders = accumulating_remainder_tree(A,m);
	auto finish = chrono::high_resolution_clock::now();

	chrono::duration<double> runtime = finish-start;

	//print_tree(remainders);
	cout << runtime.count() << endl;

}


//
//  main.cpp
//  NRM - Newton-Raphson Method (for regression problem)
//
//  Created by Zhalgas Baibatyr on 1/19/16.
//  Copyright © 2016 Zhalgas Baibatyr. All rights reserved.
//

/*

    DEGREE ----- the degree of a polynomial in regression function
    N_SAMPLES -- number of training samples
    N_FEATURES - number of given input features
    Hessian ---- Hessian matrix
    features --- input features, including intercept term (xₒ = 1)
    target ----- target (output) values
    params ----- parameters (weights) with initial values (zeros)
    hypothesis - hypothesis function
    dCost ------ derivative of a cost function

*/

#include <armadillo>

using namespace arma;

int main()
{
    /* Loading initial data: */
    mat initData;
    initData.load("../data/regression1", arma_ascii);

    /* Initializing constants: */
    const uword DEGREE = 5;
    const uword N_SAMPLES  = initData.n_rows;
    const uword N_FEATURES = initData.n_cols - 1;

    /* Transforming input data using polynomial formula: */
    mat features(N_SAMPLES, DEGREE * N_FEATURES + 1);
    features.col(0) = ones<vec>(N_SAMPLES);
    for (int i = 0; i < N_FEATURES; ++i)
    {
        for (int j = 1; j <= DEGREE; ++j)
        {
            features.col(i * DEGREE + j) = pow(initData.col(i), j);
        }
    }

    /* Preparing other data: */
    vec target = initData.col(initData.n_cols - 1);
    vec params = zeros<vec>(features.n_cols);
    vec hypothesis;
    vec dCost;
    mat Hessian;

    wall_clock timer;
    double elapsedTime;
    timer.tic();

    /* Newton-Raphson Method performs here: */
    Hessian = features.t() * features;
    while (true)
    {
        /* Calculating hypothesis values and updating parameters: */
        hypothesis = features * params;
        dCost = features.t() * (hypothesis - target) / N_SAMPLES;
        params -= Hessian.i() * dCost;
     /* params -= solve(Hessian, dCost); */

        /* Checking how close to the minimum: */
        if (norm(dCost) < 1e-5)
        {
            hypothesis = features * params;
            break;
        }
    }

    /* Measuring the performance of the algorithm: */
    elapsedTime = timer.toc();
    printf("Elapsed time: %f sec.\n\n", elapsedTime);

    mat outputData = join_rows(initData.cols(0, initData.n_cols - 2), hypothesis);
    outputData.save("outputData", arma_ascii);
    hypothesis.save("hypothesis", arma_ascii);
    params.save("params", arma_ascii);

    return EXIT_SUCCESS;
}


#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/random_convex_hull_in_disc_2.h>
#include <CGAL/Polygon_2_algorithms.h>
#include <boost/random.hpp>
#include <iostream>
#include <vector>
using namespace CGAL;

typedef Exact_predicates_inexact_constructions_kernel          K;
typedef K::Point_2                                       Point;
typedef K::FT                                                                                FT;

const double RADIUS=1.0;
int main( )
{
   int N=10000;
   std::vector<Point> v;
   boost::mt19937 gen;
   gen.seed(0u);

   random_convex_hull_in_disc_2(N,RADIUS,gen,std::back_inserter(v),K());
   size_t size = v.size();
   FT area=polygon_area_2(v.begin(),v.end(),K());
   std::cout<<"A random convex polygon inscribed in a disc with "<<size<<" vertices and area "<<area<<" has been generated."<<std::endl;

   return 0;
}


#include "testsuite.h"
#include <blitz/array.h>
#include <blitz/tinyvec2.h>

BZ_USING_NAMESPACE(blitz)

class crap {
public:
  double operator()(double x) const {return x+1;};
  BZ_DECLARE_FUNCTOR(crap);
};

template<typename T>
void test_1d(T& B)
{
  B = -2, 5, 4, 3, 1, 1;

    BZTEST(sum(B) == 12);
    BZTEST(mean(B) == 2);
    BZTEST(min(B) == -2);
    BZTEST(max(B) == 5);
    BZTEST(product(B) == -120);
    BZTEST(first(B>0) == 1);
    BZTEST(last(B>3) == 2);
    BZTEST(count(B>0) == 5);
    BZTEST(any(B>0));
    BZTEST(!any(B>10));
    BZTEST(!all(B>0));
    BZTEST(all(B>-10));

    BZTEST(all(maxIndex(B)==1));
    BZTEST(all(minIndex(B)==0));

    MinMaxValue<int> mm=minmax(B);
    BZTEST(mm.min==-2);
    BZTEST(mm.max==5);
}

// pass in an expression with value
// (-2, 5, 4, 3, 1, 1)
template<typename T>
void test_1dexpr(const T& B)
{
    BZTEST(sum(B) == 12);
    BZTEST(mean(B) == 2);
    BZTEST(min(B) == -2);
    BZTEST(max(B) == 5);
    BZTEST(product(B) == -120);
    BZTEST(first(B>0) == 1);
    BZTEST(last(B>3) == 2);
    BZTEST(count(B>0) == 5);
    BZTEST(any(B>0));
    BZTEST(!any(B>10));
    BZTEST(!all(B>0));
    BZTEST(all(B>-10));

    BZTEST(all(maxIndex(B)==1));
    BZTEST(all(minIndex(B)==0));

    MinMaxValue<typename T::T_numtype> mm=minmax(B);
    BZTEST(mm.min==-2);
    BZTEST(mm.max==5);
}

void grabner()
{
  BZ_USING_NAMESPACE(blitz::tensor)
  Array<float, 2> a1(2, 2), a2(2, 2), a3(2, 2);
  Array<float, 4> a4(2, 2, 2, 2);
  Array<float, 2> a5(2, 2), a6(2, 2);
  a1 = 1, 0, 0, 1;
  a2 = a1;
  a3 = a1;
  a4 = a1(i, k) * a2(l,k) * a3(j, l);
  a5 = sum(sum(a4, l), k);
  a6 = sum(sum(a1(i, k) * a2(l,k) * a3(j, l), l),k);
  BZTEST(all(a5==a6));
}

int main()
{
    Array<int,2> A(4,3);

    A = 0,  1, 2,
        3,  4, 5,
        6,  7, 8,
        9, 10, 11;

    BZTEST(sum(A) == 11*12/2);
    BZTEST(min(A) == 0);
    BZTEST(max(A) == 11);

    MinMaxValue<int> mm = minmax(A);
    //std::cerr << mm.min << ' ' << mm.max << std::endl;
    BZTEST(mm.min == 0);
    BZTEST(mm.max == 11);

    BZTEST(product(A) == 0);
    BZTEST(all(A >= 0));
    BZTEST(any(A == 7));
    BZTEST(count(A > 1 && A < 5) == 3);
    BZTEST(sum(pow2(A)) == 506);

    BZ_USING_NAMESPACE(blitz::tensor)

    BZTEST(sum(min(A,j)) == 0+3+6+9);
    BZTEST(sum(max(A(j,i),j)) == 9+10+11);

    Array<int,1> B(6);
    test_1d(B);
    TinyVector<int,6> Bv;
    test_1d(Bv);

    Array<int,3> C(2,2,2);
    C = 1, 0, 2, 3, 4, 7, 6, 5;

    BZTEST(sum(C) == 7*8/2);
    BZTEST(all(C <= 7));
    BZTEST(any(C == 5));
    BZTEST(!any(C == 8));
    BZTEST(sum(C(k,j,i)) == 7*8/2);
    BZTEST(sum(C(j,k,i)) == 7*8/2);

    // test behavior reported in bug 2058441
    BZTEST(sum(sum(sum(C,k),j)) == 7*8/2);
    Array<int,1> Cred(2);
    Cred=sum(sum(C,k),j);
    BZTEST(sum(Cred) == 7*8/2);
    grabner();

    mm = minmax(C);
    BZTEST(mm.min == 0);
    BZTEST(mm.max == 7);
    /* these don't work
    mm = minmax(C(i,j,k));
    BZTEST(mm.min == 0);
    BZTEST(mm.max == 7);
    mm = minmax(C(k,j,i));
    BZTEST(mm.min == 0);
    BZTEST(mm.max == 7);
    mm = minmax(C(j,k,i));
    BZTEST(mm.min == 0);
    BZTEST(mm.max == 7);
    */

    // test expression reductions

    cout << "Testing unary expression reductions\n";
    B= 2, -5, -4, -3, -1, -1;
    test_1dexpr(-B);
    cout << "Testing binary expression reductions\n";
    B= -3, 4, 3, 2, 0, 0;
    test_1dexpr(B+1);
    Array<float,1> BB(6);
    cout << "Testing function expression reductions\n";
    B=-2, 25, 16, 9, 1, 0;
    BB = 1, .5, .5, .5, 2, 0;
    test_1dexpr(pow(B,BB));
    cout << "Testing where expression reductions\n";
    B = -2, -30, 4, 3, 0, -1;
    BB = -2, 5, 3, -1, 1, 1;
    test_1dexpr(where(B>BB,B,BB));

    cout << "Testing functor expression reductions\n";
    B = -2, 5, 4, 3, 1, 1;
    crap c;
    test_1dexpr(c(B)-1);

    return 0;
}


/*
* compile with flags:   g++ test.cc softmax_classifier.cc   ../datasets/datasets.cc -std=c++14 -larmadillo -I ../../include/
* author: Yuzhen Liu
* Date: 2019.3.29 10:55
*/

#include <iostream>
#include <armadillo>
#include <svm/svm.h>
#include <svm/kernel_funcs.h>
#include <datasets/datasets.h>

using namespace std;
using namespace arma;

int main() {
    Datasets dataset = Datasets("iris");
    mat x = dataset.x.head_cols(100);
    vec y = dataset.y.head(100);
    // negative labeled as -1
    y = y.replace(0, -1);

    // // mat x = {{0, 1}, {1, 0}, {1,1}, {-1,0}, {0,-1}, {-1,-1}};
    // mat x = {{0, 1, 1, -1, 0, -1},
    //          {1, 0, 1, 0, -1, -1}};
    // vec y = {1, 1, 1, -1, -1, -1};
    // // f(X) --> y = -x;

    SVM svm = SVM();
    svm.train(x, y);
    vec res = svm.predict(x);

    printf("The sum loss is: \n");
    vec dis = res - y;
    // dis.print();
    join_rows(res, y).print();
    // cout << "The accuracy is: " << dis / (double)x.n_elem << endl;

    return 0;
}


#include <LinearModel.hpp>

#include <Eigen/Dense>
#include <Utils.hpp>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>

LinearModel::LinearModel(int weights_count, bool is_classification) : BaseModel(weights_count, is_classification) {
    weights = new double[weights_count + 1];
    // Init all weights and biases between -1.0 and 1.0
    for (int i = 0; i < weights_count + 1; i++) {
        weights[i] = ml::rand(-1, 1);
    }
}

void LinearModel::train(const Eigen::MatrixXd& train_inputs, const Eigen::MatrixXd& train_outputs, int epochs, double learning_rate) {
    const size_t sample_count = train_inputs.rows();
    const size_t inputs_size = train_inputs.cols();
    const size_t outputs_size = train_outputs.cols();

    if (is_classification) {
        std::vector<int> trainingSetOrder(sample_count);

        for (int i = 0; i < trainingSetOrder.size(); i++) {
            trainingSetOrder[i] = i;
        }

        Eigen::MatrixXd activation(sample_count, outputs_size);

        // Iterate with epochs
        for (int i = 0; i < epochs; i++) {
            // *** Predict Function ***

            // compute activation fonction
            predict(train_inputs, activation);  // or `predict(train_inputs.row(trainingSetID), activation);` in trainingSetOrder loops to predict by row

            // shuffle the training set
            ml::random_shuffle<int>(trainingSetOrder);

            // for each training set
            for (int j = 0; j < trainingSetOrder.size(); j++) {
                // select a training set ID
                int trainingSetID = trainingSetOrder[j];

                // *** Learn Function ***

                // Backpropagation of error on weights / Adjust the weights
                for (int k = 0; k < outputs_size; k++) {
                    const double target_value = train_outputs(trainingSetID, k);
                    const double actual_value = activation(trainingSetID, k);

                    double error = actual_value - target_value;
                    if (is_classification) {
                        error *= (actual_value * actual_value);
                    }

                    for (int l = 0; l < inputs_size; l++) {
                        const double entry_value = train_inputs(trainingSetID, l);

                        weights[l] -= (learning_rate * error * entry_value);
                    }
                    weights[weights_count] -= (learning_rate * error * 1);  // bias
                }
            }
        }
    } else { // to be verified
        // Add a column of one (at the right), for the bias
        Eigen::MatrixXd tmp(train_inputs.rows(), train_inputs.cols() + 1);
        Eigen::VectorXd vec(train_inputs.rows());
        for (int i = 0; i < train_inputs.rows(); i++) {
            vec(i) = 1;
        }
        tmp << train_inputs, vec;

        // Compute the transpose
        Eigen::MatrixXd inputs_transposed = tmp.transpose();
        Eigen::MatrixXd inv_inputs_transposed = (inputs_transposed * tmp).completeOrthogonalDecomposition().pseudoInverse();

        // Compute weights
        Eigen::MatrixXd w = inv_inputs_transposed * inputs_transposed * train_outputs;

        for (int i = 0; i < inputs_size + 1; i++) {
            weights[i] = w(i, 0);
        }
    }
}

double LinearModel::_activation(double value) const {
    if (is_classification) {
        value = std::tanh(value);
        return (value != 0) ? (value > 0) ? 1 : -1 : 0;
    } else {
        return value;
    }
}

void LinearModel::predict(const Eigen::MatrixXd& inputs, Eigen::MatrixXd& outputs){
    assert(inputs.rows() == outputs.rows());  // or maybe resize outputs

    // for each sample
    for (int i = 0; i < inputs.rows(); i++) {
        // Loop on outputs (here we have only one output)
        for (int j = 0; j < outputs.cols(); j++) {
            double activation = weights[weights_count];

            // Loop on inputs
            for (int k = 0; k < inputs.cols(); k++) {
                activation += inputs(i, k) * weights[k];
            }

            // compute the _sigmoid of the activation
            outputs(i, j) = _activation(activation);
        }
    }
}


#include "VectorMath.h"
#include <Eigen/Dense>
#include <random>
#include <iostream>

using namespace Eigen;

const Matrix3d VectorMath::crossProductMatrix(const Eigen::Vector3d &v)
{
    Matrix3d result;
    result << 0, -v[2], v[1],
            v[2], 0, -v[0],
            -v[1], v[0], 0;
    return result;
}

const Matrix3d VectorMath::rotationMatrix(const Vector3d &axisAngle)
{
    double theta = axisAngle.norm();
    Vector3d thetahat = axisAngle/theta;

    if(theta == 0)
        thetahat.setZero();

    Matrix3d result;
    result.setIdentity();
    result = cos(theta)*result + sin(theta)*crossProductMatrix(thetahat) + (1-cos(theta))*thetahat*thetahat.transpose();
    return result;
}

double VectorMath::randomUnitIntervalReal()
{
    return double(rand())/double(RAND_MAX);
}

const Vector3d VectorMath::axisAngle(const Matrix3d &rotationMatrix)
{
    Matrix3d I;
    I.setIdentity();
    Matrix3d RminusI = rotationMatrix - I;

    JacobiSVD<Matrix3d> svd(RminusI, ComputeFullV);
    //assert(fabs(svd.singularValues()[2]) < 1e-8);
    Vector3d axis = svd.matrixV().col(2);
    Vector3d testAxis = perpToAxis(axis);
    Vector3d resultAxis = rotationMatrix*testAxis;
    double theta = atan2(testAxis.cross(resultAxis).dot(axis), testAxis.dot(resultAxis));
    return theta*axis;
}

const Vector3d VectorMath::perpToAxis(const Vector3d &v)
{
    int mincoord = 0;
    double minval = std::numeric_limits<double>::infinity();
    for(int i=0; i<3; i++)
    {
        if(fabs(v[i]) < minval)
        {
            mincoord = i;
            minval = fabs(v[i]);
        }
    }
    Vector3d other(0,0,0);
    other[mincoord] = 1.0;
    Vector3d result = v.cross(other);
    result.normalize();
    return result;
}

const Matrix3d VectorMath::TMatrix(const Vector3d &v)
{
    double vnormsq = v.dot(v);
    Matrix3d I;
    I.setIdentity();
    if(vnormsq < 1e-8)
        return I;

    Matrix3d R = rotationMatrix(v);
    return (v*v.transpose() + (R.transpose()-I)*crossProductMatrix(v))/vnormsq;
}

const Matrix3d VectorMath::DrotVector(const Vector3d &axisangle, const Vector3d &rotatingVector)
{
    Matrix3d R = rotationMatrix(axisangle);
    Matrix3d result = -R * crossProductMatrix(rotatingVector) * TMatrix(axisangle);
    return result;
}

const Eigen::Vector3d VectorMath::randomPointOnSphere()
{
    std::random_device r;
    std::mt19937 generator(r());
    std::normal_distribution<double> distribution(0.0,1.0);
    Vector3d vec(distribution(generator), distribution(generator), distribution(generator));
    vec /= vec.norm();
    return vec;
}


/** \file  main.cpp
    \brief Test and demonstration program.
           Copyright 2006, 2010, 2013 by Erik Schloegl
     */

#include <iostream>
#include <cstdlib>
#include <boost/bind.hpp>
#include "BlackScholesAsset.hpp"
#include "Payoff.hpp"
#include "Binomial.hpp"

using namespace quantfin;

/** Test and demonstration for finite difference schemes.

    Command-line arguments:
      -# initial stock price.
         The default is 100.
      -# interest rate.
         The default is 5%.
      -# volatility.
         The default is 30%.
      -# maturity.
         The default is 1.5.
      -# moneyness.
         The default is 1 (at the money).
      -# N, time line refinement.
         The default is 10.
  */
int main(int argc,char* argv[])
{
  using std::cout;
  using std::endl;
  using std::flush;

  int i,j;
  try {
    for (i=0;i<argc;i++) cout << argv[i] << ' ';
	cout << endl;
    double S = 100.0;
    if (argc>1) S = atof(argv[1]);
    double r = 0.05;
    if (argc>2) r = atof(argv[2]);
    double sgm = 0.3;
    if (argc>3) sgm = atof(argv[3]);
    double mat = 1.5;
    if (argc>4) mat = atof(argv[4]);
    double K = 1.0;
    if (argc>5) K = atof(argv[5]);
    K *= S;
    int N = 10;
    if (argc>6) N = atoi(argv[6]);
    Array<double,1> T(N+1);
    firstIndex idx;
    double dt = mat/N;
    T = idx*dt;
    ConstVol vol(sgm);
    BlackScholesAsset stock(&vol,S);
    cout << "S: " << S << "\nK: " << K << "\nr: " << r << "\nT: " << mat << "\nsgm: " << sgm << endl;
    double CFcall = stock.option(mat,K,r);
    double CFput  = stock.option(mat,K,r,-1);
    double CFiput = stock.option(T(N/2),K,r,-1);
    cout << "Closed form call: " << CFcall << endl;
    cout << "Closed form put: " << CFput << endl;
    cout << "Closed form intermediate maturity put: " << CFiput << endl;
    cout << "Time line refinement: " << N << endl;
    cout << "Creating BinomialLattice object" << endl;
    BinomialLattice btree(stock,r,mat,N);
    Payoff call(K);
    Payoff put(K,-1);
    boost::function<double (double)> f;
    f = boost::bind(std::mem_fun(&Payoff::operator()),&call,_1);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial call (CRR): " << btree.result() << "\nDifference to closed form: " << CFcall - btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial call (JR): " << btree.result() << "\nDifference to closed form: " << CFcall - btree.result() << endl;
    f = boost::bind(std::mem_fun(&Payoff::operator()),&put,_1);
    btree.set_CoxRossRubinstein();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (CRR): " << btree.result() << "\nDifference to closed form: " << CFput - btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (JR): " << btree.result() << "\nDifference to closed form: " << CFput - btree.result() << endl;
    btree.set_Tian();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (Tian): " << btree.result() << "\nDifference to closed form: " << CFput - btree.result() << endl;
    btree.set_LeisenReimer(K);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (LR): " << btree.result() << "\nDifference to closed form: " << CFput - btree.result() << endl;
    EarlyExercise amput(put);
    boost::function<double (double,double)> g;
    g = boost::bind(boost::mem_fn(&EarlyExercise::operator()),&amput,_1,_2);
    btree.set_CoxRossRubinstein();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (CRR): " << btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (JR): " << btree.result() << endl;
    btree.set_LeisenReimer(K);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (LR): " << btree.result() << endl;

    // with dividends
    stock.dividend_yield(0.03);
    CFcall = stock.option(mat,K,r);
    CFput  = stock.option(mat,K,r,-1);
    cout << "Closed form call: " << CFcall << endl;
    cout << "Closed form put: " << CFput << endl;
    f = boost::bind(std::mem_fun(&Payoff::operator()),&call,_1);
    btree.set_CoxRossRubinstein();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial call (CRR): " << btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial call (JR): " << btree.result() << endl;
    btree.set_LeisenReimer(K);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial call (LR): " << btree.result() << endl;
    f = boost::bind(std::mem_fun(&Payoff::operator()),&put,_1);
    btree.set_CoxRossRubinstein();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (CRR): " << btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (JR): " << btree.result() << endl;
    btree.set_Tian();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (Tian): " << btree.result() << endl;
    btree.set_LeisenReimer(K);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0);
    cout << "Binomial put (LR): " << btree.result() << endl;
    btree.set_CoxRossRubinstein();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (CRR): " << btree.result() << endl;
    btree.set_JarrowRudd();
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (JR): " << btree.result() << endl;
    btree.set_LeisenReimer(K);
    btree.apply_payoff(N-1,f);
    btree.rollback(N-1,0,g);
    cout << "Binomial American put (LR): " << btree.result() << endl;
	} // end of try block

  catch (std::logic_error xcpt) {
    std::cerr << xcpt.what() << endl; }
  catch (std::runtime_error xcpt) {
    std::cerr << xcpt.what() << endl; }
  catch (...) {
    std::cerr << "Other exception caught" << endl; }

  return 0;
}


#include "tools.h"
#include "logger.h"
#include <iostream>

#include <boost/assert.hpp>
#include <boost/format.hpp>

using Eigen::VectorXd;
using Eigen::MatrixXd;
using std::vector;

static const Eigen::IOFormat HeavyFormat = Eigen::IOFormat(Eigen::StreamPrecision, 1, ", ", ";\n", "[", "]", "[", "]");

static double Cross2d(const Eigen::Vector2d &vec1, const Eigen::Vector2d &vec2) {
    return vec1[0] * vec2[1] - vec1[1] * vec2[0];
}

Eigen::Vector4d Tools::CalculateRMSE(const vector<Eigen::Vector4d> &estimations,
                                     const vector<Eigen::Vector4d> &ground_truth) {
    BOOST_ASSERT(estimations.size() == ground_truth.size());
    Eigen::Vector4d rmse;

    const size_t data_size = estimations.size();
    if (data_size < 1) {
        BOOST_LOG_TRIVIAL(error) << (boost::format("Got invalid size, estimations.size()=%zu, ground_truth.size()=%zu.")
                                     % estimations.size() % ground_truth.size()).str();
        return rmse;
    }

    Eigen::Map<const Eigen::Array4Xd> estimations_map(reinterpret_cast<const double*>(estimations.data()),
                                                      4, data_size);
    Eigen::Map<const Eigen::Array4Xd> ground_truth_map(reinterpret_cast<const double*>(ground_truth.data()),
                                                       4, data_size);
    rmse = ((estimations_map - ground_truth_map).square().rowwise().sum() / data_size).sqrt();
    BOOST_LOG_TRIVIAL(info) << (boost::format("rmse=%s") % rmse.transpose().format(HeavyFormat)).str();
    return rmse;
}

Eigen::Matrix<double, 3, 4> Tools::CalculateJacobian(const VectorXd& x_state) {
   auto J = Eigen::Matrix<double, 3, 4>();
   const double &px = x_state[0];
   const double &py = x_state[1];
   const double &vx = x_state[2];
   const double &vy = x_state[3];
   const double p_norm = x_state.topRows<2>().norm();
   const double p_norm2 = p_norm * p_norm;

   if (std::abs(p_norm) < 1e-6) {
       return J;
   }

   J <<
       // row1
       px / p_norm, py / p_norm, 0.0, 0.0,
       // row2
       -py / p_norm2, px / p_norm2, 0.0, 0.0,
       // row3
       py * (Cross2d(x_state.bottomRows<2>(), x_state.topRows<2>())) / (p_norm * p_norm2),
       px * (Cross2d(x_state.topRows<2>(), x_state.bottomRows<2>())) / (p_norm * p_norm2),
       px / p_norm, py / p_norm;

    return J;
}


/// @file  eval.hpp
/// @brief Declarations for evaluation methods

#pragma once
#ifndef OGT_EVAL_EVAL_HPP
#define OGT_EVAL_EVAL_HPP

#include <ogt/config.hpp>
#include <ogt/util/chain_merge.hpp>
#include <Eigen/Dense>
#include <functional>
#include <vector>

namespace OGT_NAMESPACE {
namespace eval {

/// Calculate raw stress. This is the sum of the squared error of the distances.
/// It takes its minimum at zero, which indicates a perfect embedding.
/// If requested, the estimated distances can first be scaled by the optimal
/// constant to minimize stress.
/// The scaled versions of these values can be used to compare embeddings of the
/// same dataset, but as they are not normalized they cannot be compared across
/// datasets.
///
/// The unscaled version is referred to as \sigma_r in:
/// [1] I. Borg & P. Groenen (1997): Modern multidimensional scaling: theory
///     and applications. Springer.
double mdsStress(const Eigen::MatrixXd& dhat, const Eigen::MatrixXd& dtrue,
	bool scaled = false);

/// Calculate normed stress. This is a normalized version of mdsStress(), which
/// can thus be compared between different datasets.
/// It takes its minimum at zero, which indicates a perfect embedding.
///
/// The unscaled version is referred to as Stress-1 or \sigma_1 in:
/// [1] I. Borg & P. Groenen (1997): Modern multidimensional scaling: theory
///     and applications. Springer.
double mdsNormedStress(const Eigen::MatrixXd& dhat,
	const Eigen::MatrixXd& dtrue, bool scaled = false);

/// Calculate normed rank stress. That is, the normalized sum-squared amount by
/// which each similarity constraint is violated.
/// This essentially treats dist(i,j) as the target distance for dist(k,l)
/// if dist(i,j) immediately precedes dist(k,l) in the partial order of
/// distances.
double mdsNormedRankStress(const Eigen::MatrixXd& dhat,
	const OGT_NAMESPACE::util::ChainMerge& order);

/// Calculate the root mean squared error of the distances, after finding the
/// scaling which minimizes this error.
/// In other words, we report RMSE for the best linear fit between the
/// distance matrices.
double distRmse(const Eigen::MatrixXd& dhat, const Eigen::MatrixXd& dtrue);

/// Calculate the Kendall's tau-b of two distance vectors to other points.
/// Does so in O(n log n) time, using
/// Knight's Algorithm](http://adereth.github.io/blog/2013/10/30/efficiently-computing-kendalls-tau/).
double kendallTau(const Eigen::VectorXd& d1, const Eigen::VectorXd& d2);

/// Calculate the mean Kendall's tau-b of rankings by each row.
double meanKendallTau(const Eigen::MatrixXd& dhat,
	const Eigen::MatrixXd& dtrue);

/// Calculate the weighted Kendall's tau of two vectors of numbers.
/// The tau value is given for vectors r and s. The function w provides
/// a weight for each rank in the list.
///
/// [1] S. Vigna, A Weighted Correlation Index for Rankings with Ties. WWW, 2015
double weightedTau(const Eigen::VectorXd& r, const Eigen::VectorXd& s,
	std::function<double(size_t /* rank */)> w);

/// Calculate the weighted Kendall's tau of two vectors of numbers.
/// The tau value is given for vectors r and s. The functions w1 and w2 provide
/// weights for each rank in the list.
///
/// [1] S. Vigna, A Weighted Correlation Index for Rankings with Ties. WWW, 2015
double weightedTau(const Eigen::VectorXd& r, const Eigen::VectorXd& s,
	std::function<double(size_t /* rank */)> w1,
	std::function<double(size_t /* rank */)> w2);

/// The hyperbolic tau: weightedTau with rank weight 1/(1 + r).
double hyperbolicTau(const Eigen::VectorXd& r, const Eigen::VectorXd& s);

/// Calculate the mean hyperbolic tau of rankings by each row.
double meanHyperbolicTau(const Eigen::MatrixXd& dhat,
	const Eigen::MatrixXd& dtrue);

} // end namespace eval
} // end namespace OGT_NAMESPACE
#endif /* OGT_EVAL_EVAL_HPP */


// (C) Copyright John Maddock 2006
// 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)

#ifdef _MSC_VER
#  pragma warning(disable: 4512) // assignment operator could not be generated.
#  pragma warning(disable: 4510) // default constructor could not be generated.
#  pragma warning(disable: 4610) // can never be instantiated - user defined constructor required.
#endif

#include <iostream>
#include <iomanip>
#include <boost/math/distributions/binomial.hpp>

void find_max_sample_size(double p, unsigned successes)
{
   //
   // p         = success ratio.
   // successes = Total number of observed successes.
   //
   // Calculate how many trials we can have to ensure the
   // maximum number of successes does not exceed "successes".
   // A typical use would be failure analysis, where you want
   // zero or fewer "successes" with some probability.
   //
   using namespace std;
   using namespace boost::math;

   // Print out general info:
   cout <<
      "________________________\n"
      "Maximum Number of Trials\n"
      "________________________\n\n";
   cout << setprecision(7);
   cout << setw(40) << left << "Success ratio" << "=  " << p << "\n";
   cout << setw(40) << left << "Maximum Number of \"successes\" permitted" << "=  " << successes << "\n";
   //
   // Define a table of confidence intervals:
   //
   double alpha[] = { 0.5, 0.25, 0.1, 0.05, 0.01, 0.001, 0.0001, 0.00001 };
   //
   // Print table header:
   //
   cout << "\n\n"
           "____________________________\n"
           "Confidence        Max Number\n"
           " Value (%)        Of Trials \n"
           "____________________________\n";
   //
   // Now print out the data for the table rows.
   //
   for(unsigned i = 0; i < sizeof(alpha)/sizeof(alpha[0]); ++i)
   {
      // Confidence value:
      cout << fixed << setprecision(3) << setw(10) << right << 100 * (1-alpha[i]);
      // calculate trials:
      double t = binomial_distribution<>::find_maximum_number_of_trials(successes, p, alpha[i]);
      t = floor(t);
      // Print Trials:
      cout << fixed << setprecision(0) << setw(15) << right << t << endl;
   }
   cout << endl;
}

int main()
{
   find_max_sample_size(1.0/1000, 0);
   find_max_sample_size(1.0/10000, 0);
   find_max_sample_size(1.0/100000, 0);
   find_max_sample_size(1.0/1000000, 0);

   return 0;
}


//
//  FunctionsTest.cpp
//  Cynapse
//
//

#include <Eigen/Dense>

#include "catch.hpp"
#include "../Functions.hpp"

TEST_CASE("Functions sigmoid", "[Functions]") {
    REQUIRE(sigmoid(1000) == 1.0);
    REQUIRE(sigmoid(0.0) == 0.5);
    REQUIRE(sigmoid(-1000) == 0.0);
}

TEST_CASE("Functions sigmoid_derivative", "[Functions]") {
    REQUIRE(sigmoid_derivative(1000) == 0.0);
    REQUIRE(sigmoid_derivative(0.0) == 0.25);
    REQUIRE(sigmoid_derivative(-1000) == 0.0);
}

TEST_CASE("Functions heaviside", "[Functions]") {
    REQUIRE(heaviside(0.49) == 0.0);
    REQUIRE(heaviside(0.5) == 1.0);
    REQUIRE(heaviside(0.51) == 1.0);
}

TEST_CASE("Functions quadratic_cost_derivative", "[Functions]") {
    Eigen::MatrixXd m(2,2);
    m(0,0) = 3;
    m(1,0) = 2.5;
    m(0,1) = -1;
    m(1,1) = 4;

    Eigen::MatrixXd n(2,2);
    m(0,0) = 10;
    m(1,0) = -3.5;
    m(0,1) = -6;
    m(1,1) = 2;

    Eigen::MatrixXd result = m - n;
    REQUIRE(quadratic_cost_derivative(m, n) == result);
}


/*****************************************************************************
*
* Rokko: Integrated Interface for libraries of eigenvalue decomposition
*
* Copyright (C) 2012-2015 Rokko Developers https://github.com/t-sakashita/rokko
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*****************************************************************************/

#ifndef ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP
#define ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP

#include <cmath>
#include <stdexcept>
#include <boost/throw_exception.hpp>
#include <rokko/localized_matrix.hpp>

namespace rokko {

class laplacian_matrix {
public:
  template<typename T>
  static void multiply(int dim, const T* x, T* y) {
    y[0] = x[0] - x[1];
    y[dim-1] = 2 * x[dim-1] - x[dim - 2];
    for (int k = 1; k < (dim-1); ++k) { // from 1 to end-1
      y[k] = - x[k-1] + 2 * x[k] - x[k+1];
    }
  }

  template<typename T>
  static void multiply(int dim, const std::vector<T>& v, std::vector<T>& w) {
    multiply(dim, &v[0], &w[0]);
  }

  template<typename T, typename MATRIX_MAJOR>
  static void generate(rokko::localized_matrix<T, MATRIX_MAJOR>& mat) {
    if (mat.rows() != mat.cols())
      BOOST_THROW_EXCEPTION(std::invalid_argument("laplacian_matrix::generate() : non-square matrix"));
    mat.setZero();
    int n = mat.rows();
    mat(0, 0) = 1; mat(0, 1) = -1;
    mat(n-1, n-2) = -1;  mat(n-1, n-1) = 2;
    for(int i = 1; i < n-1; ++i) {
      mat(i, i-1) = -1;
      mat(i, i) = 2;
      mat(i, i+1) = -1;
    }
  }

  // calculate k-th smallest eigenvalue of dim-dimensional Laplacian matrix (k=0...dim-1)
  static double eigenvalue(int dim, int k) {
    return 2 * (1 - std::cos(M_PI * (2 * k + 1) / (2 * dim + 1)));
  }
};

} // namespace rokko

#endif // ROKKO_UTILITY_LAPLACIAN_MATRIX_HPP


// HardCoded.cpp
//
// C++ code to price an option, essential algorithms.
//
// We take CEV model with a choice of the elaticity parameter
// and the Euler method. We give option price and number of times
// S hits the origin.
//
// (C) Datasim Education BC 2008-2011
//
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include "OptionData.hpp"
#include "UtilitiesDJD/RNG/NormalGenerator.hpp"
#include "UtilitiesDJD/Geometry/Range.cpp"
#include <cmath>
#include <iostream>

template <class T> void print(const std::vector<T>& myList)
{  // A generic print function for vectors

	std::cout << std::endl << "Size of vector is " << l.size() << "\n[";

	// We must use a const iterator here, otherwise we get a compiler error.
	std::vector<T>::const_iterator i;
	for (i = myList.begin(); i != myList.end(); ++i)
	{
		std::cout << *i << ",";

	}

	std::cout << "]\n";
}
template <typename Type>
boost::tuple<Type, Type> SDSE(const std::vector<Type>& price, const Type& r, const Type& T)
{
	Type temp1(0), temp2(0);
	for (int i = 0; i < price.size(); i++)
	{
		temp1 += price[i] * price[i];
		temp2 += price[i];
	}

	int M = price.size();
	Type sd = sqrt(temp1 - 1 / M * temp2 * temp2) * exp(-2 * r * T) / (M - 1);
	Type se = sd / sqrt(M);

	return boost::make_tuple(sd, se);
}
namespace SDEDefinition
{ // Defines drift + diffusion + data

	OptionData* data;				// The data for the option MC

	double drift(double t, double X)
	{ // Drift term

		return (data->r) * X; // r - D
	}

	double diffusion(double t, double X)
	{ // Diffusion term

		double betaCEV = 1.0;
		return data->sig * pow(X, betaCEV);

	}

	double diffusionDerivative(double t, double X)
	{ // Diffusion term, needed for the Milstein method

		double betaCEV = 1.0;
		return 0.5 * (data->sig) * (betaCEV)*pow(X, 2.0 * betaCEV - 1.0);
	}
} // End of namespace

int main()
{
	std::cout << "1 factor MC with explicit Euler" << endl;

	// Store Batch 1 to Batch 2 data in a vector.
	typedef boost::tuple<double, double, double, double, double> TupleFive;
	vector<TupleFive> vecBatch;
	vecBatch.push_back(boost::make_tuple(0.25, 65.0, 0.30, 0.08, 60.0));
	vecBatch.push_back(boost::make_tuple(1.00, 100.0, 0.20, 0.00, 100.0));
	//Batch 4: T = 30.0, K = 100.0, sig = 0.30, r = 0.08, S = 100.0 (C = 92.17570, P = 1.24750)
	//vecBatch.push_back(boost::make_tuple(30.00, 100.0, 0.30, 0.08, 100.0));

	// Vector to store the prices of put and call.
	vector<double> vecCallPrice, vecPutPrice;
	for (int i = 0; i < vecBatch.size(); i++)
	{
		OptionData myOption;
		myOption.T = vecBatch[i].get<0>();
		myOption.K = vecBatch[i].get<1>();
		myOption.sig = vecBatch[i].get<2>();
		myOption.r = vecBatch[i].get<3>();
		myOption.type = 1;
		double S_0 = vecBatch[i].get<4>();
		long N = 100;
		std::cout << "Number of subintervals in time: ";
		std::cin >> N;

		// Create the basic SDE (Context class)
		Range<double> range(0.0, myOption.T);
		double VOld = S_0;
		double VNew;

		std::vector<double> x = range.mesh(N);

		// V2 mediator stuff
		long NSim = 50000;
		std::cout << "Number of simulations: ";
		std::cin >> NSim;

		double k = myOption.T / double(N);
		double sqrk = sqrt(k);

		// Normal random number
		double dW;
		// Call option price.
		double price1 = 0.0;
		// Put option price.
		double price2 = 0.0;

		// NormalGenerator is a base class
		NormalGenerator* myNormal = new BoostNormal();

		using namespace SDEDefinition;
		SDEDefinition::data = &myOption;

		std::vector<double> res;
		int coun = 0; // Number of times S hits origin

		// A.
		for (long i = 1; i <= NSim; ++i)
		{ // Calculate a path at each iteration

			if ((i / 10000) * 10000 == i)
			{// Give status after each 1000th iteration

				std::cout << i << std::endl;
			}

			VOld = S_0;
			for (unsigned long index = 1; index < x.size(); ++index)
			{

				// Create a random number
				dW = myNormal->getNormal();

				// The FDM (in this case explicit Euler)
				VNew = VOld + (k * drift(x[index - 1], VOld))
					+ (sqrk * diffusion(x[index - 1], VOld) * dW);

				VOld = VNew;

				// Spurious values
				if (VNew <= 0.0) coun++;
			}
			double tmp1 = myOption.myPayOffFunction(VNew);
			price1 += (tmp1) / double(NSim);
			vecCallPrice.push_back(tmp1);
			myOption.type = -1;
			double tmp2 = myOption.myPayOffFunction(VNew);
			price2 += (tmp2) / double(NSim);
			vecPutPrice.push_back(tmp2);
			myOption.type = 1;
		}

		// D. Finally, discounting the average price.
		price1 *= exp(-myOption.r * myOption.T);
		price2 *= exp(-myOption.r * myOption.T);

		// Cleanup; V2 use scoped pointer
		delete myNormal;

		std::cout << "Price, after discounting: Call = " << price1 << ", Put = " << price2 << std::endl;
		std::cout << "Number of times origin is hit: " << coun << endl;

		// Print SD and SE.
		boost::tuple<double, double> tupleCall = SDSE<double>(vecCallPrice, myOption.r, myOption.T);
		boost::tuple<double, double> tuplePut = SDSE<double>(vecPutPrice, myOption.r, myOption.T);
		std::cout << "Batch " << i + 1 << ", Call: NT = " << N << ", NSIM = " << NSim
			<< ", SD = " << tupleCall.get<0>() << ", SE = " << tupleCall.get<1>() << endl;
		std::cout << "Batch " << i + 1 << ", Put: NT = " << N << ", NSIM = " << NSim
			<< ", SD = " << tuplePut.get<0>() << ", SE = " << tuplePut.get<1>() << endl;
	}
	return 0;
}


//------------------------------------------------------------------------------
/// \file OptionalMonad_tests.cpp
/// \ref Ivan Čukić, Functional Programming in C++,  Manning Publications;
/// 1st edition (November 19, 2018). ISBN-13: 978-1617293818
//------------------------------------------------------------------------------
#include "Categories/Monads/OptionalMonad.h"

#include <boost/test/unit_test.hpp>
#include <optional>
#include <string>

using Categories::Monads::OptionalMonad::endomorphism_morphism_map;
using Categories::Monads::OptionalMonad::multiplication_component;

BOOST_AUTO_TEST_SUITE(Categories)
BOOST_AUTO_TEST_SUITE(Monads)
BOOST_AUTO_TEST_SUITE(OptionalMonad_tests)

// cf. Čukić (2018), Ch. 10

std::optional<std::string> user_full_name(const std::string& login)
{
  return {};
}

std::optional<std::string> to_html(const std::string& text)
{
  return {};
}

std::optional<std::string> usable_user_full_name(const std::string& login)
{
  if (login == "None")
  {
    return {};
  }

  return std::make_optional<std::string>(login);
}

std::optional<std::string> usable_to_html(const std::string& text)
{
  if (text == "No address")
  {
    return {};
  }

  return std::make_optional<std::string>(text);
}

// Testfunctions act as morphisms f : X \to T(Y) where T is the endomorphism.
// T : X \to T(X), where T(X) is of type std::optional
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(TestFunctionsBehavesAsAMorphism)
{
  {
    const std::string test_name {"Jean-Francois Roberval"};
    // result of morphism f of type T(Y), as f : X \to T(Y)
    const auto result = usable_user_full_name(test_name);
    BOOST_TEST(static_cast<bool>(result));
    BOOST_TEST((result.value() == "Jean-Francois Roberval"));
  }
  {
    const std::string test_name {"None"};
    // result of morphism f of type T(Y), as f : X \to T(Y)
    const auto result = usable_user_full_name(test_name);
    BOOST_TEST(!static_cast<bool>(result));
  }
  {
    const std::string test_address {"lapresse.ca"};
    // result of morphism f of type T(Y), as f : X \to T(Y)
    const auto result = usable_to_html(test_address);
    BOOST_TEST(static_cast<bool>(result));
    BOOST_TEST((result.value() == "lapresse.ca"));
  }
  {
    const std::string test_address {"No address"};
    // result of morphism f of type T(Y), as f : X \to T(Y)
    const auto result = usable_to_html(test_address);
    BOOST_TEST(!static_cast<bool>(result));
  }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(EndomorphismMorphismMapWorksOnFunctionReturningStdOptional)
{
  const auto test_full_name =
    std::make_optional<std::string>("Jacques Cartier");

  BOOST_TEST_REQUIRE((test_full_name.value() == "Jacques Cartier"));
  BOOST_TEST_REQUIRE(static_cast<bool>(test_full_name));

  const auto result =
    endomorphism_morphism_map(test_full_name, usable_user_full_name);

  BOOST_TEST(static_cast<bool>(result));
  BOOST_TEST((result.value() == test_full_name.value()));
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(ComposeMorphismMapWithMultiplicationComponent)
{
  const auto test_full_name =
    std::make_optional<std::string>("Samuel de Champlain");

  const auto result =
    multiplication_component(
      endomorphism_morphism_map(test_full_name, usable_user_full_name));

  BOOST_TEST(static_cast<bool>(result));
  BOOST_TEST((result.value() == test_full_name.value()));
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(UseMainFromOptionalMonadExampleFromCukic)
{
  std::optional<std::string> login;

  multiplication_component(
    endomorphism_morphism_map(
      multiplication_component(
        endomorphism_morphism_map(
          login,
          user_full_name)),
      to_html));

  auto login_and_user_full_name =
    multiplication_component(
      endomorphism_morphism_map(
        multiplication_component(
          endomorphism_morphism_map(
            login,
            user_full_name)),
        to_html));

  BOOST_TEST(true);
}

BOOST_AUTO_TEST_SUITE_END() // OptionalMonad_tests
BOOST_AUTO_TEST_SUITE_END() // Monads
BOOST_AUTO_TEST_SUITE_END() // Categories


//  (C) Copyright John Maddock 2006.
//  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)

#ifndef BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
#define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP

#ifdef _MSC_VER
#pragma once
#endif

#include <boost/math/special_functions/legendre.hpp>
#include <boost/math/tools/workaround.hpp>
#include <complex>

namespace boost{
namespace math{

namespace detail{

//
// Calculates the prefix term that's common to the real
// and imaginary parts.  Does *not* fix up the sign of the result
// though.
//
template <class T, class Policy>
inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol)
{
   BOOST_MATH_STD_USING

   if(m > n)
      return 0;

   T sin_theta = sin(theta);
   T x = cos(theta);

   T leg = detail::legendre_p_imp(n, m, x, static_cast<T>(pow(fabs(sin_theta), T(m))), pol);

   T prefix = boost::math::tgamma_delta_ratio(static_cast<T>(n - m + 1), static_cast<T>(2 * m), pol);
   prefix *= (2 * n + 1) / (4 * constants::pi<T>());
   prefix = sqrt(prefix);
   return prefix * leg;
}
//
// Real Part:
//
template <class T, class Policy>
T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol)
{
   BOOST_MATH_STD_USING  // ADL of std functions

   bool sign = false;
   if(m < 0)
   {
      // Reflect and adjust sign if m < 0:
      sign = m&1;
      m = abs(m);
   }
   if(m&1)
   {
      // Check phase if theta is outside [0, PI]:
      T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
      if(mod < 0)
         mod += 2 * constants::pi<T>();
      if(mod > constants::pi<T>())
         sign = !sign;
   }
   // Get the value and adjust sign as required:
   T prefix = spherical_harmonic_prefix(n, m, theta, pol);
   prefix *= cos(m * phi);
   return sign ? T(-prefix) : prefix;
}

template <class T, class Policy>
T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol)
{
   BOOST_MATH_STD_USING  // ADL of std functions

   bool sign = false;
   if(m < 0)
   {
      // Reflect and adjust sign if m < 0:
      sign = !(m&1);
      m = abs(m);
   }
   if(m&1)
   {
      // Check phase if theta is outside [0, PI]:
      T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
      if(mod < 0)
         mod += 2 * constants::pi<T>();
      if(mod > constants::pi<T>())
         sign = !sign;
   }
   // Get the value and adjust sign as required:
   T prefix = spherical_harmonic_prefix(n, m, theta, pol);
   prefix *= sin(m * phi);
   return sign ? T(-prefix) : prefix;
}

template <class T, class U, class Policy>
std::complex<T> spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol)
{
   BOOST_MATH_STD_USING
   //
   // Sort out the signs:
   //
   bool r_sign = false;
   bool i_sign = false;
   if(m < 0)
   {
      // Reflect and adjust sign if m < 0:
      r_sign = m&1;
      i_sign = !(m&1);
      m = abs(m);
   }
   if(m&1)
   {
      // Check phase if theta is outside [0, PI]:
      U mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<U>());
      if(mod < 0)
         mod += 2 * constants::pi<U>();
      if(mod > constants::pi<U>())
      {
         r_sign = !r_sign;
         i_sign = !i_sign;
      }
   }
   //
   // Calculate the value:
   //
   U prefix = spherical_harmonic_prefix(n, m, theta, pol);
   U r = prefix * cos(m * phi);
   U i = prefix * sin(m * phi);
   //
   // Add in the signs:
   //
   if(r_sign)
      r = -r;
   if(i_sign)
      i = -i;
   static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)";
   return std::complex<T>(policies::checked_narrowing_cast<T, Policy>(r, function), policies::checked_narrowing_cast<T, Policy>(i, function));
}

} // namespace detail

template <class T1, class T2, class Policy>
inline std::complex<typename tools::promote_args<T1, T2>::type>
   spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
   typedef typename tools::promote_args<T1, T2>::type result_type;
   typedef typename policies::evaluation<result_type, Policy>::type value_type;
   return detail::spherical_harmonic<result_type, value_type>(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol);
}

template <class T1, class T2>
inline std::complex<typename tools::promote_args<T1, T2>::type>
   spherical_harmonic(unsigned n, int m, T1 theta, T2 phi)
{
   return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>());
}

template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
   spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
   typedef typename tools::promote_args<T1, T2>::type result_type;
   typedef typename policies::evaluation<result_type, Policy>::type value_type;
   return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_r(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)");
}

template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
   spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi)
{
   return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>());
}

template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
   spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
   typedef typename tools::promote_args<T1, T2>::type result_type;
   typedef typename policies::evaluation<result_type, Policy>::type value_type;
   return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_i(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)");
}

template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
   spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi)
{
   return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>());
}

} // namespace math
} // namespace boost

#endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP


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

void eigenValueSolver()
{
    // ComplexEigenSolver<MatrixXcf> ces;
    Eigen::EigenSolver<Eigen::MatrixXd> ces;
    Eigen::MatrixXd A(4, 4);
    A(0, 0) = 18;
    A(0, 1) = -9;
    A(0, 2) = -27;
    A(0, 2) = 24;
    A(1, 0) = -9;
    A(1, 1) = 4.5;
    A(1, 2) = 13.5;
    A(1, 3) = -12;
    A(2, 0) = -27;
    A(2, 1) = 13.5;
    A(2, 2) = 40.5;
    A(2, 3) = -36;
    A(3, 0) = 24;
    A(3, 1) = -12;
    A(3, 2) = -36;
    A(3, 3) = 32;
    ces.compute(A);
    std::cout << "The eigenvalues of A are:" << std::endl
         << ces.eigenvalues() << std::endl;
    std::cout << "The matrix of eigenvectors, V, is:" <<std::endl
         << ces.eigenvectors() << std::endl
         << std::endl;
    //  complex<float> lambda =  ces.eigenvalues()[0];
    //  cout << "Consider the first eigenvalue, lambda = " << lambda << endl;
    //  VectorXcf v = ces.eigenvectors().col(0);
    //  cout << "If v is the corresponding eigenvector, then lambda * v = " <<
    //  endl << lambda * v << endl;
    //  cout << "... and A * v = " << endl << A * v << endl << endl;
    //
    //  cout << "Finally, V * D * V^(-1) = " << endl
    //       << ces.eigenvectors() * ces.eigenvalues().asDiagonal() *
    //       ces.eigenvectors().inverse() << endl;
}

int main()
{

}


#ifndef _EMBEDDINGSTORE_H
#define _EMBEDDINGSTORE_H

#include <Eigen/Dense>
#include <Eigen/Core>
#include "word2vec.hpp"
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include "IEmbeddingModel.hpp"
#include "vpTree.hpp"
#include "math.h"
#include <map>

using namespace std;
using namespace Eigen;

class EmbeddingStore
{
    private:
        static double eucl_dist(const VectorXf& a, const VectorXf& b)
        {
            double dist = 0 ;
            for(int i = 0; i < a.size(); i++)
                dist += pow( a[i] - b[i],2);
            return sqrt(dist);
        }
        static double cosine_dist(const VectorXf& a, const VectorXf& b)
        {
            double dot = 0, norm_1 = 0, norm_2 = 0;
            for(int i = 0; i < a.size(); i++)
            {
                dot += a[i] * b[i];
                norm_1 += pow(a[i], 2);
                norm_2 += pow(b[i], 2);
            }

            return dot / (sqrt(norm_1)* sqrt(norm_2) );
        }
        //Am I sure that here should be a vector?
        vector<string> vocab;
        vector<VectorXf> vectors;
        map<string, int> word2index;
        //unordered_map<VectorXf, string> v2w;
        MatrixXf Embeddings;
        VpTree<VectorXf, eucl_dist> EmbeddingTree;

    public:
    VectorXf operator[](string word);
    EmbeddingStore();
    ~EmbeddingStore();
    EmbeddingStore(IEmbeddingModel &model);
    MatrixXd readMatrix(const char *filename);
    void writeMatrix(const char *filename, MatrixXd mat);
    void find_k_nierest(string word, int k,
                       vector<string>& results, vector<double>& dists);

    void dbscan(float eps, int minPts);
    float similarity();

    VectorXf get_sif(string sentence, map<string, int> tf, float alpha);
    string find_nierest(string word);
};

#endif


#include <cassert>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <fstream>
#include <initializer_list>
#include <iostream>
#include <ostream>
#include <random>
#include <string>
#include <vector>

#include <Eigen/Core>
#include <Eigen/LU>

using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::seq;

MatrixXd read_tableau(const std::string& filePath) {
  std::ifstream file(filePath);
  if(!file.is_open())
    throw std::ifstream::failure("File could not be opened");
  int m, n;
  file >> m >> n;
  MatrixXd tableau(m+1, n+1);
  for (int i = 0; i < m + 1; i++)
      for (int j = 0; j < n + 1; j++)
        file >> tableau(i, j);
  file.close();
  return tableau;
}

auto initialize(int m, int n) {
  VectorXd x(n), y(m), s(n);
  double mu;
  std::random_device r;
  std::default_random_engine engine(r());
  std::uniform_real_distribution<> u_dist(-1.0, 1.0);
  double positive_lower = std::nextafter(0, std::numeric_limits<double>::max());
  // Positive uniform distribution
  std::uniform_real_distribution<> u_dist_pos(positive_lower, 1.0);
  for(int i = 0; i < n; i++) {
    x(i) = u_dist_pos(engine);
    s(i) = u_dist_pos(engine);
  }
  for (int i = 0; i < m; i++)
    y(i) = u_dist(engine);
  mu = u_dist_pos(engine);
  return std::make_tuple(x, y, s, mu);
}

double get_alpha(const VectorXd& vec, const VectorXd& delta_vec) {
  assert(vec.size() == delta_vec.size());
  int size = vec.size();
  double alpha = std::numeric_limits<double>::max();
  bool all_delta_nonnegative= true;
  double ratio;
  for(int i = 0; i < size; i++)
    if(delta_vec(i) < 0 && (ratio = -(vec(i) / delta_vec(i))) < alpha) {
      alpha = ratio;
      all_delta_nonnegative = false;
    }
  return all_delta_nonnegative ? 1.0 : alpha;
}

auto interior_point(const MatrixXd& A, const VectorXd& b, const VectorXd& c,
                    double eps = 10e-6, double max_norm = 10e6,
                    int k_max = 1000) {
  int m = A.rows(), n = A.cols();
  assert(m == b.size());
  assert(n == c.size());
  double sq_norm, max_sq_norm = std::pow(max_norm, 2);
  constexpr double fraction = 1 - 10e-7;
  double theta = (n > 13) ? (1 - 3.5 / std::sqrt(n)) : 0.5;
  auto [x, y, s, mu] = initialize(m, n);
  int k = 0;
  do {
    MatrixXd S = s.asDiagonal();
    MatrixXd D = (x.array() / s.array()).matrix().asDiagonal();
    VectorXd rho_P = b - A * x;
    VectorXd rho_D = c - A.transpose() * y - s;
    VectorXd v = (mu - (x.array() * s.array())).matrix().transpose();
    VectorXd delta_y = -((A * D * A.transpose()).inverse() *
                         (A * S.inverse() * v - A * D * rho_D - rho_P));
    VectorXd delta_s = -(A.transpose() * delta_y) + rho_D;
    VectorXd delta_x = S.inverse() * v - D * delta_s;
    double alpha = fraction * std::min(get_alpha(x, delta_x),
                                       get_alpha(s, delta_s));
    VectorXd x_new = x + alpha * delta_x;
    VectorXd y_new = y + alpha * delta_y;
    VectorXd s_new = s + alpha * delta_s;

    // Concatenate vectors.
    VectorXd joined(x.size() + y.size() + s.size());
    joined << x, y, s;
    VectorXd joined_new(x_new.size() + y_new.size() + s_new.size());
    joined_new << x_new, y_new, s_new;
    sq_norm = (joined_new - joined).squaredNorm();
    // sq_norm = std::max({
    //     (x_new - x).squaredNorm(),
    //     (y_new - y).squaredNorm(),
    //     (s_new - s).squaredNorm()
    //   });
    x = x_new;
    y = y_new;
    s = s_new;
    mu *= theta;
    k++;
  } while((x.transpose() * s > eps) &&
          (k < k_max) &&
          (sq_norm < max_sq_norm));
  if(x.transpose() * s < eps)
    return std::make_tuple(x, y);
  else if(sq_norm > max_sq_norm)
    throw std::invalid_argument("Algorithm did not converge. Norm exceeded.");
  else
    throw std::invalid_argument("Algorithm did not converge."
                                "Number of maximum iterations exceeded.");
}

int main(int argc, char** argv) {
  // Process command-line arguments
  std::string file_path = "";
  std::vector<std::string> args(argv + 1, argv + argc);
  for(auto arg = args.begin(); arg != args.end(); arg++) {
    if(*arg == "-i")
      file_path = *(++arg);
  }
  if(file_path.empty()) {
    std::cout << "USAGE: pdip -i <file>" << std::endl;
    return EXIT_FAILURE;
  }

  MatrixXd tableau;
  try {
    tableau = read_tableau(file_path);
  }
  catch(std::ifstream::failure& ex) {
    std::cout << ex.what() << std::endl;
    return EXIT_FAILURE;
  }
  auto start = std::chrono::steady_clock::now();

  int m = tableau.rows() - 1, n = tableau.cols() - 1;
  MatrixXd A = tableau(seq(0, m-1), seq(0, n-1));
  VectorXd b = tableau(seq(0, m-1), n);
  VectorXd c = tableau(m, seq(0, n-1));

  VectorXd x_sum = VectorXd::Zero(n);
  VectorXd y_sum = VectorXd::Zero(m);
  int n_runs = 30;
  for (int i = 0; i < n_runs; i++) {
    auto [x, y] = interior_point(A, b, c, 10e-10);
    x_sum += x;
    y_sum += y;
  }

  std::cout << "Average solutions after " << n_runs << " executions:"
            << std::endl;
  VectorXd x_avg = x_sum.transpose().array() / n_runs;
  VectorXd y_avg = y_sum.transpose().array() / n_runs;

  auto end = std::chrono::steady_clock::now();

  std::cout << "x:" << std::endl << x_avg << std::endl;
  std::cout << std::endl;
  std::cout << "y:" << std::endl << y_avg << std::endl;
  std::cout << std::endl;
  std::cout << "optimum:" << std::endl << x_avg.dot(c) << std::endl;
  std::cout << std::endl;
  std::cout << "Running time: "
            << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / n_runs
            << '\n';
  return EXIT_SUCCESS;
}


#include "boost/numeric/ublas/make_unbounded_array.hpp"

#include "boost/numeric/ublas/Newton.hpp"
#include "boost/numeric/ublas/Davidon_Fletcher_Powell.hpp"
#include <boost/numeric/ublas/io.hpp>

#include "test.hpp"

void print(const boost::numeric::ublas::Function<> & f, const vector_t & solution, double epsilon, std::size_t number_iteration) {
    std::cout << "Precision:            " << epsilon << std::endl;
    std::cout << "Number of iterations: " << number_iteration << std::endl;
    std::cout << "Function value:       " << f(solution) << std::endl;
    std::cout << "Computed solution:    " << solution << std::endl << std::endl;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cout.precision(10);
    using namespace boost::numeric::ublas;

    auto epsilon = 1E-9;
    std::size_t number_iteration = 0;
    vector_t solution;

    Function<> f(2, function, gradient, hessian);
    //vector_t x(make_unbounded_array({ -1.2, 1.0 }));
    vector_t x(make_unbounded_array({ -0.5, 0.5 }));
    //vector_t x(make_unbounded_array({ -8.0, 9.0 }));

    solution = DavidonFletcherPowell(f, x, epsilon, number_iteration = 0);
    std::cout << "Davidon-Fletcher-Powell:" << std::endl;
    print(f, solution, epsilon, number_iteration);

    solution = Newton(f, x, epsilon, number_iteration = 0);
    std::cout << "Newton:" << std::endl;
    print(f, solution, epsilon, number_iteration);

    return 0;
}


#ifndef RKIMPLEMENTER

#define RKIMPLEMENTER

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

/**
 *
 * Implementation of an explicit Runge Kutta Solver. See the documentation for more information.
 *
 */
template <class Step> class ExplicitRungeKuttaIntegrator {

    public:
        /**
         * Constructor for the ExplicitRungeKuttaIntegrator
         *
         * @param A the coefficients matrix A of a butcher scheme
         * @param b the weights vector for a butcher scheme. Note that we are taking a column vector whereas in a butcher tableau this would be a row vector (though doesn't matter if one uses VectorXd in Eigen).
         */
        ExplicitRungeKuttaIntegrator(const Eigen::MatrixXd &A, const Eigen::VectorXd &b):A(A),b(b),size(A.cols()){
        }

        /**
         * The solve methods applies an explicit Runge Kutta method to a given ODE
         *
         * @param f the function we are integrating over
         * @param time the time interval we want to integrate over
         * @param y0 the initial state of the system
         * @param steps the number of integration steps we would like to make (number of steps equals number of runge kutta method evaluations)
         *
         * @return a std::vector of states, one for every integration step performed. The first step will be the supplied y0.
         */
        template<typename Function>
        std::vector<Step> solve(Function &&f, double time, const Step &y0, unsigned int steps){

            std::vector<Step> stepsVector;

            // as advertised the first position will be our initial state
            stepsVector.push_back(y0);

            // knowing the total time and number of steps allows us to calculate the time we integrate over every step
            double h = time / steps;

            // now we call the solver "steps" times to do the actual integration
            for(unsigned int i = 0; i < steps; i++){
                // integrate and directly add to our list
                stepsVector.push_back(iteration(f,stepsVector.back(),h));
            }

            return stepsVector;

        }

    private:
        /**
         * This function computes on single runge kutta step and returns its result.
         *
         * @param f the function we are integrating over
         * @param y0 the starting value (the initial value or the previous step's result)
         * @param h the step size
         *
         * @return the computation of one runge kutta step
         */
        template<typename Function>
        Step iteration(Function &&f, Step &y0, const double h){

            // initialize current step as previous step
            Step y1 = y0;

            // temporary vector to store the increments
            std::vector<Step> increments;

            // calculate an increment per loop iteration
            for(unsigned int i = 0; i < size; i++){

                Step increment = y0;
                // second loop to account for dependency of current increments on previous increments
                for(unsigned int k = 0; k < i; k++){
                    increment += h*A(i,k) * increments[k];
                }

                // store the increment
                increments.push_back(f(increment));
            }

            // now we add the increments with correct weights to y0 which we already copied over to y1
            for(unsigned int i = 0; i < size; i++){
                y1 += h*b(i) *increments[i];
            }

            return y1;

        }

        const Eigen::MatrixXd A;
        const Eigen::VectorXd b;
        unsigned int size;
};

template <typename Step> class ImplicitRungeKuttaIntegrator {

    public:
        ImplicitRungeKuttaIntegrator(const Eigen::MatrixXd &A, const Eigen::VectorXd &b) : A(A),b(b),size(A.cols()){
        }

        /**
         * The solve methods applies an implicit Runge Kutta method to a given ODE
         *
         * @param f the function we are integrating over
         * @param the Jacobian of f, needed for finding 0 (newton method) to solve for stages.
         * @param time the time interval we want to integrate over
         * @param y0 the initial state of the system
         * @param steps the number of integration steps we would like to make (number of steps equals number of runge kutta method evaluations)
         *
         * @return a std::vector of states, one for every integration step performed. The first step will be the supplied y0.
         */
        template<typename Function, typename Jacobian>
        std::vector<Step> solve(Function &&f, Jacobian && J, double time, const Step &y0, unsigned int steps){

            std::vector<Step> stepsVector;

            // as advertised the first position will be our initial state
            stepsVector.push_back(y0);

            // knowing the total time and number of steps allows us to calculate the time we integrate over every step
            double h = time / steps;

            // now we call the solver "steps" times to do the actual integration
            for(unsigned int i = 0; i < steps; i++){
                // integrate and directly add to our list
                stepsVector.push_back(iteration(f,stepsVector.back(),h));
            }

            return stepsVector;

        }

    private:
        /**
         * This function computes on single runge kutta step and returns its result. This method uses
         *
         * @param f the function we are integrating over
         * @param y0 the starting value (the initial value or the previous step's result)
         * @param h the step size
         *
         * @return the computation of one runge kutta step
         */
        template<typename Function, typename Jacobian>
        Step iteration(Function &&f, Jacobian && J, Step &y0, const double h){

            throw "not yet implemented";
            // TODO

        }

    private:
        const Eigen::MatrixXd A;
        const Eigen::VectorXd b;
        unsigned int size;
};

// a collection of optimization methods needed for implicit runge-kutta methods
namespace OptimizationMethods{

    /**
     * Takes a function f, its derivative J as well as a starting point x0 and finds the root x' with f(x') = 0
     * Source: Adapted from 'C++ code 8.4.4.5' of the book https://www.sam.math.ethz.ch/~grsam/NCSE19/NumCSE_Lecture_Document.pdf
     *
     * @param f the function whose root we want to find
     * @param J the jacobian of f
     * @param x0 the starting value for the newton iteration
     * @param reltol if the difference between two iterations is smaller than rtol*x', with x' a likely root, we stop the iteration
     * @param abstol if the difference between two iterations is smaller than abstol we stop the iteration
     *
     * @exception if the function does not converge an error will be thrown
     *
     *
     * @return the root of f (the value x where f(x) = 0)
     *
     */
    template<typename Step, typename Function, typename Jacobian>
    Step dampedNewton(Function &&f, Jacobian &&J, Step x0, double reltol = 1e-7, double abstol=1e-8){

        // first we check the dimensionality of the function
        uint32_t n = x0.size();
        Step correction(n), tentativeCorrection(n);
        Step x(n);
        Step xTemp(n);
        double correctionNorm, tentativeCorrectionNorm;

        // convergence variables
        double lambda = 1.0;
        double lmin = 1E-3;

        do {
            // calculate the difference to the next iterate
            auto jacobianLUFactorized = J(x).lu();
            correction = jacobianLUFactorized.solve(f(x));
            correctionNorm = correction.norm();

            do {
                // reduction of damping factor
                lambda /= 2;
                // check for non convergence
                if(lambda < lmin){
                    throw "No convergence";
                }
                // tentative next iterate
                xTemp = x-lambda*correction;
                tentativeCorrection = jacobianLUFactorized.solve(f(xTemp));
                tentativeCorrectionNorm = tentativeCorrection.norm();
            } while(tentativeCorrectionNorm > (1-lambda/2)*correctionNorm);
            // we accept the new step
            x = xTemp;
            // we somewhat reduce the damping
            lambda = std::min(2*lambda,1.0);
        } while((tentativeCorrectionNorm > reltol*x.norm()) && tentativeCorrectionNorm > abstol);
    }
}

#endif


#include "matrix_add_subtract.h"
#include "common/pixel_benchmark.h"

#include <opencv2/opencv.hpp>
#include <Eigen/Dense>

static void matrix_add_f32_opencv(float* mA, float* mB, float* mC, size_t M, size_t N)
{
    cv::Size size;
    size.height = M;
    size.width = N;
    cv::Mat matA = cv::Mat(size, CV_32FC1, mA);
    cv::Mat matB = cv::Mat(size, CV_32FC1, mB);
    cv::Mat matC = cv::Mat(size, CV_32FC1, mC);
    cv::add(matA, matB, matC);
}

static void matrix_add_f32_eigen(float* mA, float* mB, float* mC, size_t M, size_t N)
{
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eA(mA, M, N);
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eB(mB, M, N);
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eC(mC, M, N);
    eC = eA + eB;
}

//----------------------------------------------------------------------

static void matrix_subtract_f32_opencv(float* mA, float* mB, float* mC, size_t M, size_t N)
{
    cv::Size size;
    size.height = M;
    size.width = N;
    cv::Mat matA = cv::Mat(size, CV_32FC1, mA);
    cv::Mat matB = cv::Mat(size, CV_32FC1, mB);
    cv::Mat matC = cv::Mat(size, CV_32FC1, mC);
    cv::subtract(matA, matB, matC);
}

static void matrix_subtract_f32_eigen(float* mA, float* mB, float* mC, size_t M, size_t N)
{
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eA(mA, M, N);
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eB(mB, M, N);
    Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> eC(mC, M, N);
    eC = eA - eB;
}

static void matrix_add_f32_test()
{
    cv::Mat image = cv::imread("river_bank2.png");
    std::vector<cv::Mat> channels;
    cv::split(image, channels);
    cv::Mat b_channels = channels[0];
    cv::Mat g_channels = channels[1];
    cv::Mat r_channels = channels[2];

    b_channels.convertTo(b_channels, CV_32FC1);
    g_channels.convertTo(g_channels, CV_32FC1);
    r_channels.convertTo(r_channels, CV_32FC1);

    cv::Size size = image.size();
    size_t height = size.height; // M
    size_t width = size.width; // N
    printf("image info: height=%zu, width=%zu\n", height, width);

    float* mA = (float*)b_channels.data;
    float* mB = (float*)g_channels.data;

    size_t buf_size = sizeof(float)*height*width;
    float* mC_opencv = (float*)malloc(buf_size);
    float* mC_eigen = (float*)malloc(buf_size);
    float* mC_naive = (float*)malloc(buf_size);
    float* mC_asimd = (float*)malloc(buf_size);
    double t_start, t_cost;

    t_start = pixel_get_current_time();
    matrix_add_f32_eigen(mA, mB, mC_eigen, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_add_f32, eigen, time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_add_f32_opencv(mA, mB, mC_opencv, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_add_f32, opencv, time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_add_f32_naive(mA, mB, mC_naive, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_add_f32, naive,  time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_add_f32_asimd(mA, mB, mC_asimd, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_add_f32, asimd,  time cost %.2lf ms\n", t_cost);

    // validate result, check if they are match
    int mis_opencv = 0;
    int mis_eigen = 0;
    int mis_asimd = 0;
    size_t len = height * width;
    for (size_t i=0; i<len; i++) {
        if (mC_naive[i]!=mC_opencv[i]) {
            mis_opencv ++;
        }

        if (mC_naive[i]!=mC_eigen[i]) {
            mis_eigen ++;
        }

        if (mC_naive[i]!=mC_asimd[i]) {
            mis_asimd ++;
        }
    }
    printf("mis_opencv=%d, mis_eigen=%d, mis_asimd=%d\n", mis_opencv, mis_eigen, mis_asimd);

}

static void matrix_subtract_f32_test()
{
    cv::Mat image = cv::imread("river_bank2.png");
    std::vector<cv::Mat> channels;
    cv::split(image, channels);
    cv::Mat b_channels = channels[0];
    cv::Mat g_channels = channels[1];
    cv::Mat r_channels = channels[2];

    b_channels.convertTo(b_channels, CV_32FC1);
    g_channels.convertTo(g_channels, CV_32FC1);
    r_channels.convertTo(r_channels, CV_32FC1);

    cv::Size size = image.size();
    size_t height = size.height; // M
    size_t width = size.width; // N
    printf("image info: height=%zu, width=%zu\n", height, width);

    float* mA = (float*)b_channels.data;
    float* mB = (float*)g_channels.data;

    size_t buf_size = sizeof(float)*height*width;
    float* mC_opencv = (float*)malloc(buf_size);
    float* mC_eigen = (float*)malloc(buf_size);
    float* mC_naive = (float*)malloc(buf_size);
    float* mC_asimd = (float*)malloc(buf_size);
    double t_start, t_cost;

    t_start = pixel_get_current_time();
    matrix_subtract_f32_eigen(mA, mB, mC_eigen, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_subtract_f32, eigen, time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_subtract_f32_opencv(mA, mB, mC_opencv, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_subtract_f32, opencv, time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_subtract_f32_naive(mA, mB, mC_naive, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_subtract_f32, naive,  time cost %.2lf ms\n", t_cost);

    t_start = pixel_get_current_time();
    matrix_subtract_f32_asimd(mA, mB, mC_asimd, height, width);
    t_cost = pixel_get_current_time() - t_start;
    printf("matrix_subtract_f32, asimd,  time cost %.2lf ms\n", t_cost);

    // validate result, check if they are match
    int mis_opencv = 0;
    int mis_eigen = 0;
    int mis_asimd = 0;
    size_t len = height * width;
    for (size_t i=0; i<len; i++) {
        if (mC_naive[i]!=mC_opencv[i]) {
            mis_opencv ++;
        }

        if (mC_naive[i]!=mC_eigen[i]) {
            mis_eigen ++;
        }

        if (mC_naive[i]!=mC_asimd[i]) {
            mis_asimd ++;
        }
    }
    printf("mis_opencv=%d, mis_eigen=%d, mis_asimd=%d\n", mis_opencv, mis_eigen, mis_asimd);

}

int main() {

    matrix_add_f32_test();
    matrix_subtract_f32_test();

    return 0;
}


#include <mona/utility.hpp>
#include <mona/targets/png.hpp>
#include <mona/axes3.hpp>
#include <mona/surface_mesh.hpp>

#include <armadillo>

auto f(double x, double y)
{
    return (2*x*x + y*y) * std::exp(1 - x*x -y*y);
};

template <typename F>
auto get_surface(F f)
{
    arma::fvec line = mona::linspace(-2, 2, 50);
    auto [x, y] = mona::meshgrid(line, line);
    auto z = mona::apply(f, x, y);

    auto mesh = mona::surface_mesh(x, y, z);

    return mesh;
}

int main()
{
    auto png  = mona::png(800, 600);
    auto axes = mona::axes3({-4, 4}, {-4, 4}, {-4, 4}, 5);
    auto surf = get_surface(f);

    axes.submit(surf);
    png.save(axes, "image.png");
}


#include <iostream>
#include <Eigen/Dense>
#include "ReferenceModel.hpp"

using namespace Eigen;
using namespace std;

int main(void)
{
    cout << "Started" << endl;
    ReferenceModel_Config_t config_model_z;
    // Reference model
    config_model_z.A        = MatrixXd::Zero(2,2);
    config_model_z.B        = MatrixXd::Zero(2,1);
    config_model_z.states0  = VectorXd::Zero(2);
    config_model_z.dt       = 1.0/200.0;
    config_model_z.A(0,0)   =  0.0;
    config_model_z.A(0,1)   =  1.0;
    config_model_z.A(1,0)   = -5.416;
    config_model_z.A(1,1)   = -7.027;
    config_model_z.B(0,0)   = -0.1145;
    config_model_z.B(1,0)   =  6.273;

    cout << config_model_z.A;

    ReferenceModel model;
    model.initialize(config_model_z);

    for(int i=0; i<1000; i++)
    {
        if (i >= 200)
        {
            VectorXd inputs = VectorXd::Zero(1);
            inputs(0) = -0.5;
            model.update(inputs);
        }
        else
            model.update(VectorXd::Zero(1));

        VectorXd outputs;
        model.get_outputs(outputs);

        cout << i << "," << outputs(0) << endl;

    }
    return 0;
}


#include <cmath>
#include <memory>

#include <Eigen/Geometry>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/float64.hpp"
#include "sensor_msgs/msg/imu.hpp"

using namespace std::chrono_literals;
using std::placeholders::_1;

double normaliseAngle(double x)
{
  x = fmod(x + M_PI, 2*M_PI);
  if (x < 0)
    x += 2*M_PI;
  return x - M_PI;
}

Eigen::Vector3d ToEulerAngles(Eigen::Quaterniond q)
{
  Eigen::Vector3d angles;

  // roll (x-axis rotation)
  double sinr_cosp = 2 * (q.w() * q.x() + q.y() * q.z());
  double cosr_cosp = 1 - 2 * (q.x() * q.x() + q.y() * q.y());
  angles(0) = std::atan2(sinr_cosp, cosr_cosp);

  // pitch (y-axis rotation)
  double sinp = 2 * (q.w() * q.y() - q.z() * q.x());
  if (std::abs(sinp) >= 1)
    angles(1) = std::copysign(M_PI / 2, sinp); // use 90 degrees if out of range
  else
    angles(1) = std::asin(sinp);

  // yaw (z-axis rotation)
  double siny_cosp = 2 * (q.w() * q.z() + q.x() * q.y());
  double cosy_cosp = 1 - 2 * (q.y() * q.y() + q.z() * q.z());
  angles(2) = std::atan2(siny_cosp, cosy_cosp);

  return angles;
}

class Imu2rpy : public rclcpp::Node
{
public:
  Imu2rpy()
      : Node("imu_to_rpy")
  {
    imu_sub_ = this->create_subscription<sensor_msgs::msg::Imu>(
        "imu", 10, std::bind(&Imu2rpy::imu_callback, this, _1));

    roll_publisher_ = this->create_publisher<std_msgs::msg::Float64>("roll", 10);
    pitch_publisher_ = this->create_publisher<std_msgs::msg::Float64>("pitch", 10);
    yaw_publisher_ = this->create_publisher<std_msgs::msg::Float64>("yaw", 10);

    roll_rate_publisher_ = this->create_publisher<std_msgs::msg::Float64>("roll_rate", 10);
    pitch_rate_publisher_ = this->create_publisher<std_msgs::msg::Float64>("pitch_rate", 10);
    yaw_rate_publisher_ = this->create_publisher<std_msgs::msg::Float64>("yaw_rate", 10);
  }

private:

  void imu_callback(const sensor_msgs::msg::Imu::SharedPtr msg)
  {
    Eigen::Quaterniond q(msg->orientation.w, msg->orientation.x, msg->orientation.y, msg->orientation.z);
    //auto euler = q.toRotationMatrix().eulerAngles(2, 1, 0);
    auto euler = ToEulerAngles(q);

    double roll = euler(0);
    double pitch = euler(1);
    double yaw = euler(2);

    //std::string message1 = "w=" + std::to_string(q.w()) + ", x= " + std::to_string(q.x()) +
    //  ", y= " + std::to_string(q.y()) + ", z= " + std::to_string(q.z());
    //RCLCPP_INFO(this->get_logger(), "Incoming quaternion '%s'", message1.c_str());

    //std::string message2 = "roll=" + std::to_string(roll) + ", pitch= " + std::to_string(pitch) + ", yaw= " + std::to_string(yaw);
    //RCLCPP_INFO(this->get_logger(), "Converted euler angles '%s'", message2.c_str());

    //Eigen::Quaterniond q2 = Eigen::AngleAxisd(roll, Eigen::Vector3d::UnitX()) *
    //  Eigen::AngleAxisd(pitch, Eigen::Vector3d::UnitY()) *
    //  Eigen::AngleAxisd(yaw, Eigen::Vector3d::UnitZ());

    //std::string message3 = "w=" + std::to_string(q2.w()) + ", x= " + std::to_string(q2.x()) +
    //  ", y= " + std::to_string(q2.y()) + ", z= " + std::to_string(q2.z());
    //RCLCPP_INFO(this->get_logger(), "Converted quaternion '%s'\n", message3.c_str());

    auto roll_msg = std_msgs::msg::Float64();
    roll_msg.data = roll;

    auto pitch_msg = std_msgs::msg::Float64();
    pitch_msg.data = pitch;

    auto yaw_msg = std_msgs::msg::Float64();
    yaw_msg.data = yaw;

    auto roll_rate_msg = std_msgs::msg::Float64();
    roll_rate_msg.data = msg->angular_velocity.x;

    auto pitch_rate_msg = std_msgs::msg::Float64();
    pitch_rate_msg.data = msg->angular_velocity.y;

    auto yaw_rate_msg = std_msgs::msg::Float64();
    yaw_rate_msg.data = msg->angular_velocity.z;

    roll_publisher_->publish(roll_msg);
    pitch_publisher_->publish(pitch_msg);
    yaw_publisher_->publish(yaw_msg);
    roll_rate_publisher_->publish(roll_rate_msg);
    pitch_rate_publisher_->publish(pitch_rate_msg);
    yaw_rate_publisher_->publish(yaw_rate_msg);
  }

  rclcpp::Subscription<sensor_msgs::msg::Imu>::SharedPtr imu_sub_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr roll_publisher_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr pitch_publisher_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr yaw_publisher_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr roll_rate_publisher_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr pitch_rate_publisher_;
  rclcpp::Publisher<std_msgs::msg::Float64>::SharedPtr yaw_rate_publisher_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<Imu2rpy>());
  rclcpp::shutdown();
  return 0;
}


/**
 * @file categorical.hpp
 * @author Vahid Bastani
 *
 * implementation of categorical (multinomial) distribution
 */
#ifndef SSMPACK_DISTRIBUTION_CATEGORICAL_HPP
#define SSMPACK_DISTRIBUTION_CATEGORICAL_HPP

#include "ssmkit/random/generator.hpp"

#include <armadillo>

namespace ssmkit {
namespace distribution {

/** Categorical (multinomial) distribution
 *
 * \f{equation}{p(x|\mathbf{p}) = \mathcal{Cat}(\mathbf{p})\f}
 * where \f$\mathbf{p} = [p_0, \cdots, p_N]^T\f$ and \f$p(x=i|\mathbf{p}) = p_i\f$
 */
class Categorical {
  //! Type of the parameter vector \f$\mathbf{p}\f$.
  using TParameterVar = arma::vec;
  //! Type of the random variable \f$x\f$.
  using TValueType = unsigned int;

 private:
 //! The parameter vector \f$\mathbf{p}\f$.
 TParameterVar param_;
 //! Cumulative distribution function.
 TParameterVar cdf_;
 //! Core random number distribution.
 std::uniform_real_distribution<double> uniform_;
 //! Length of the parameter vector \f$N+1\f$.
 TValueType max_;

 public:
  //! Default constructor \f$\mathbf{p}=[1.0]\f$.
  Categorical() : Categorical(arma::ones<arma::vec>(1)) {}
  /** Constructor
   * @param parameter The parameter vector \f$\mathbf{p}\f$.
   * @pre The sum of the elements of \p parameter should be 1.0.
   */
  Categorical(TParameterVar parameters)
      : param_(std::move(parameters)) {calcCDF(); calcMax();}
  //! Return a random variable from the distribution.
  TValueType random() {
    double rv = uniform_(random::Generator::get().getGenerator());
    for (TValueType i = 0; i < max_; ++i)
      if (rv < cdf_(i))
        return i;

    return 0; // this line never get reached
  }
  //! Return likelihood of the given random variable
  double likelihood(const TValueType &rv) {
    return param_(rv);
  }

  /** Change parameters of the distribution
   * @param parameter The parameter vector \f$\mathbf{p}\f$.
   * @pre The sum of the elements of \p parameter should be 1.0.
   */
  Categorical &parameterize(const TParameterVar & param){
    param_ = param;
    calcCDF();
    calcMax();
    return *this;
  }

  private:
   void calcCDF() { cdf_ = arma::cumsum(param_); }
   void calcMax() { max_ = param_.n_rows; }
};

} // namespace ssmkit
} // namespace distribution

#endif //SSMPACK_DISTRIBUTION_CATEGORICAL_HPP


#pragma once

#include "numeric/dense_matrix.hpp"
#include <Eigen/Geometry>

/// \file jacobian_determinant.hpp

namespace neon
{
namespace detail
{
template <typename matrix_type>
[[nodiscard]] auto jacobian_determinant(matrix_type const& jacobian)
{
    return jacobian.determinant();
}

[[nodiscard]] inline auto jacobian_determinant(matrix32 const& jacobian)
{
    return jacobian.col(0).cross(jacobian.col(1)).norm();
}

[[nodiscard]] inline auto jacobian_determinant(matrix31 const& jacobian) { return jacobian.norm(); }
}

/**
 * Compute the Jacobian determinant for a volume or surface mapping.  In three
 * dimensions it performs the following operation:
 * \f{align*}{
 *     j &= \det \begin{bmatrix}
 *             \frac{\partial x}{\partial \xi} & \frac{\partial x}{\partial \eta} & \frac{\partial
 * x}{\partial \zeta} \\
 *             \frac{\partial y}{\partial \xi} & \frac{\partial y}{\partial \eta} & \frac{\partial
 * y}{\partial \zeta} \\ \frac{\partial z}{\partial \xi} & \frac{\partial z}{\partial \eta} &
 * \frac{\partial z}{\partial \zeta} \end{bmatrix} \f}
 *
 * However the determinant for non-square Jacobian is not defined.  When there
 * is a mapping from \f$ \mathbb{R}^3 \f$ to \f$ \mathbb{R}^2 \f$ the Jacobian
 * `determinant' can be computed by
 * \f{align*}{
 *     j &= || \mathbf{x}_{,\mathbf{\xi}} \times \mathbf{x}_{,\mathbf{\eta}} ||
 * \f}
 * where the Jacobian is given by the non-square matrix
 * \f{align*}{
 *    & \begin{bmatrix}
 *          \frac{\partial x}{\partial \xi} & \frac{\partial x}{\partial \eta} \\
 *          \frac{\partial y}{\partial \xi} & \frac{\partial y}{\partial \eta} \\
 *          \frac{\partial z}{\partial \xi} & \frac{\partial z}{\partial \eta}
 *      \end{bmatrix}
 * \f}
 * This is useful when the surface is described by a two dimensional
 * element but there are only three dimensional coordinates \cite Anton1998.
 */
template <typename matrix_expression>
[[nodiscard]] inline auto jacobian_determinant(matrix_expression const& jacobian)
{
    return detail::jacobian_determinant(jacobian.eval());
}
}


#define BOOST_TEST_MODULE test SPH_2D
#include <boost/test/included/unit_test.hpp>
#include <boost/test/tools/floating_point_comparison.hpp>
#include <boost/test/parameterized_test.hpp>
#include <boost/bind.hpp>

#include "SPH_2D.h"
#include "file_writer.h"

using namespace boost::unit_test;
namespace tt=boost::test_tools;

SPH_main domain;

/*
 * Spline Functions Tests
 */
BOOST_AUTO_TEST_SUITE(TestSplineFunctions, * description("Testsing Cubic Spline Functions"));

BOOST_AUTO_TEST_CASE(TestCubicSplineLess,  * description("Distance between 0 and 1"))
{
    domain.h = 1.;
    double dn[2] = { 0.5 , 0. };
    double tres = domain.cubic_spline(dn);
    double res = 10.0 * (1.0 - 1.5 * 1/4 + 0.75 * 1/8) / (7.0 * M_PI);
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(TestCubicSplineGreater, * description("Distance between 1 and 2"))
{
    domain.h = 1.;
    double dn[2] = {1, 0};
    double tres = domain.cubic_spline(dn);
    double res = 10  * 0.25 / (7 * M_PI);
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(TestCubicSplineOutsite, * description("Distance outside the spline"))
{
    domain.h = 1.;
    double dn[2] = {2, 1};
    double tres = domain.cubic_spline(dn);
    double res = 0;
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(TestCubicSplineFirstLess, \
* description("First derivative of distance between 0 and 1"))
{
    domain.h = 1.;
    double dn[2] = {0.5, 0};
    double tres = domain.cubic_spline_first_derivative(dn);
    double res = 10 * (-3 * 0.5 + 2.25 * 1/4) / (7 * M_PI);
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(TestCubicSplineFirstGreater, \
* description("First derivative of distance between 1 and 2"))
{
    domain.h = 1.;
    double dn[2] = {1, 0};
    double tres = domain.cubic_spline_first_derivative(dn);
    double res = -10 * 0.75 / (7 * M_PI);
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_CASE(TestCubicSplineFirstOutside, \
* description("First derivative of distance outside the spline"))
{
    domain.h = 1.;
    double dn[2] = {2., 1.};
    double tres = domain.cubic_spline_first_derivative(dn);
    double res = 0;
    BOOST_TEST(tres == res, tt::tolerance(0.0001));
}

BOOST_AUTO_TEST_SUITE_END();

/*
 * Gradient Function Tests
 */

BOOST_AUTO_TEST_SUITE(TestGradient, * description("Testing the Gradient Update Function"));

BOOST_AUTO_TEST_CASE(TestGradientLess, * description("Distance between 0 and 1"))
{
    SPH_particle* p1 = new SPH_particle();
    SPH_particle* p2 = new SPH_particle();

    domain.h = 1.;
    domain.mass = 1.;
    domain.mu = 1.;

    p1->v[0] = 1.;
    p1->v[1] = 0.;
    p1->rho = 1.;
    p1->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;
    p1->D = 0.;

    p2->v[0] = 0.;
    p2->v[1] = 0.;
    p2->rho = 1.;
    p2->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;

    double dn[2] = {0.5 , 0};

    domain.update_gradients(dn, p1, p2);

    double res = (10 * (-3 * 0.5 + 2.25 * 1/4) / (7 * M_PI));

    BOOST_TEST(2 * res == p1->a[0], tt::tolerance(0.0001));
    BOOST_TEST(res == p1->D, tt::tolerance(0.0001));
    BOOST_TEST(0 == p1->a[1], tt::tolerance(0.0001));

    delete p1;
    delete p2;

    // Need to check a and D
}

BOOST_AUTO_TEST_CASE(TestGradientGreater, * description("Distance between 1 and 2"))
{
    SPH_particle* p1 = new SPH_particle();
    SPH_particle* p2 = new SPH_particle();

    domain.h = 1.;
    domain.mass = 1.;
    domain.mu = 1.;

    p1->v[0] = 1.;
    p1->v[1] = 1.;
    p1->rho = 1.;
    p1->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;
    p1->D = 0.;

    p2->v[0] = 0.;
    p2->v[1] = 0.;
    p2->rho = 1.;
    p2->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;

    double dn[2] = {1 , 0};

    domain.update_gradients(dn, p1, p2);

    double res = -10 * 0.75 / (7 * M_PI);

    BOOST_TEST(2 * res == p1->a[1], tt::tolerance(0.0001));
    BOOST_TEST(res == p1->D, tt::tolerance(0.0001));
    BOOST_TEST(0 == p1->a[0], tt::tolerance(0.0001));

    delete p1;
    delete p2;
    // Need to check a and D
}

BOOST_AUTO_TEST_CASE(TestGradinetOutside, * description("Distance outside the spline"))
{
    SPH_particle* p1 = new SPH_particle();
    SPH_particle* p2 = new SPH_particle();

    domain.h = 1.;
    domain.mass = 1.;
    domain.mu = 1.;

    p1->v[0] = 1.;
    p1->v[1] = 0.;
    p1->rho = 1.;
    p1->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;
    p1->D = 0.;

    p2->v[0] = 0.;
    p2->v[1] = 0.;
    p2->rho = 1.;
    p2->P = 1.;
    p1->a[0] = 0.;
    p1->a[1] = 0.;

    double dn[2] = {2 , 1};

    domain.update_gradients(dn, p1, p2);

    BOOST_TEST(0 == p1->a[0], tt::tolerance(0.0001));
    BOOST_TEST(0 == p1->D, tt::tolerance(0.0001));
    BOOST_TEST(0 == p1->a[1], tt::tolerance(0.0001));

}

BOOST_AUTO_TEST_SUITE_END();


#pragma once

#include <armadillo>
#include <iostream>
#include <unordered_map>
#include <cmath>
#include <Eigen/Dense>
// using Eigen::ArrayXi;
using namespace std;
// using namespace arma;
using ArrayXL = Eigen::Array<int64_t, Eigen::Dynamic, 1>;

struct shannonEntropy {

    typedef unordered_map<uint64_t, size_t> histoMap;
//    typedef unordered_map<int, double> probMap;

    static shannonEntropy::histoMap calcDistribution(const ArrayXL &seq) {
        shannonEntropy::histoMap histo;
        for (const uint64_t &v: seq) {
            shannonEntropy::histoMap::iterator it = histo.find(v);
            if (it == histo.end()) {
                histo.insert(std::make_pair(v, 1));
            }else{
                it->second = it->second + 1;
            }
        }
        return histo;
    }

    static double calcProbability(const shannonEntropy::histoMap &histo, const ArrayXL &seq) {
        double scale = 1.0 / seq.size();
        double H=0;
        for(auto v: histo) {
            double prob = v.second * scale;
            H = H - (prob * log2(prob));
        }
        return H;
    }

    static double calc(const ArrayXL &seq) {
        shannonEntropy::histoMap histo = shannonEntropy::calcDistribution(seq);
//        for(auto v: histo) {
//            cout << v.first << ": " << v.second << endl;
//        }
        double prob = shannonEntropy::calcProbability(histo, seq);
        return prob;
    }
};


#pragma once
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <vector>

#include "stiffness_matrix.hpp"

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

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

//----------------AssembleMatrixBegin----------------
//! Assemble the stiffness matrix
//! for the linear system
//!
//! @param[out] A will at the end contain the Galerkin matrix
//! @param[in] vertices a list of triangle vertices
//! @param[in] triangles a list of triangles
template<class Matrix>
void assembleStiffnessMatrix(Matrix& A, const Eigen::MatrixXd& vertices,
                            const Eigen::MatrixXi& triangles)
{

    const int numberOfElements = triangles.rows();
    A.resize(vertices.rows(), vertices.rows());

    std::vector<Triplet> triplets;

    triplets.reserve(numberOfElements * 3 * 3);
    //// ANCSE_START_TEMPLATE
    for (int i = 0; i < numberOfElements; ++i) {
        auto& indexSet = triangles.row(i);

        const auto& a = vertices.row(indexSet(0));
        const auto& b = vertices.row(indexSet(1));
        const auto& c = vertices.row(indexSet(2));

        Eigen::Matrix3d stiffnessMatrix;
        computeStiffnessMatrix(stiffnessMatrix, a, b, c);

        for (int n = 0; n < 3; ++n) {
            for (int m = 0; m < 3; ++m) {
                auto triplet = Triplet(indexSet(n), indexSet(m), stiffnessMatrix(n, m));
                triplets.push_back(triplet);
            }
        }
    }
    //// ANCSE_END_TEMPLATE
    A.setFromTriplets(triplets.begin(), triplets.end());
}
//----------------AssembleMatrixEnd----------------


#include <boost/multiprecision/cpp_int.hpp>
#include <cmath>
#include <iostream>
#include <string>

using namespace std;
using boost::multiprecision::cpp_int;

/*
We need to find the n-digit integers that are also an n'th power. i.e. a 3 digit number that is also a third power.
So the integers we need to find are.. 10 ^ (n - 1) <= x ^ n < 10 ^ n;

Or in other words if the function L gets length of an integer then we need:
L(x ^ n) = n.

If our base is x then the maximum it can be is 9 and lowest it can be is 1.
Then we just need to get maximum value of n, which will be given by taking the log and solving for n >.
For x = 9, largest possible n = 22, so we have our upperlimits.
*/

int digitCount(cpp_int n) {
	int digits = 0;
	while(n) {
		n /= 10;
		digits++;
	}
	return digits;
}

int main(int argc, char *argv[]) {
	int result = 0;
	for(int x = 1; x < 10; x++) {
		for(int n = 1; n < 22; n++) {
			if(digitCount(boost::multiprecision::pow((cpp_int)x, n)) == n) {
				result++;
			}
		}
	}
	cout << result << endl;
	return 0;
}