///
/// @author  Thomas Lehmann
/// @file    factorial.cxx
/// @brief   factorial function
///
/// Copyright (c) 2015 Thomas Lehmann
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
/// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
/// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
/// and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies
/// or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
/// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
/// DAMAGES OR OTHER LIABILITY,
/// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <generator/select.h>
#include <math/big_integer.h>
#include <math/big_integer_configurator.h>
#include <performance/measurement.h>

#include <boost/program_options.hpp>
#include <vector>
#include <cstdint>

/// @struct options
/// @brief parsed command line options
struct Options {
    uint64_t max_n; ///! factorial: n!
    bool all;       ///! when true showing each factorial
};

/// @param argc number of parameters
/// @param argv array of parameters
/// @param options where to store the parsed command line options
/// @return true when all is fine and application can use the option(s).
static bool parse(int argc, char** argv, Options& options) {
    namespace po = boost::program_options;
    po::options_description description("Allowed options for tool 'factorial'");
    description.add_options()
        ("help", "print this help")
        ("n", po::value<uint64_t>(&options.max_n)->default_value(100),
         "Calculating factorial: n! (default: 100)")
        ("all", po::value<bool>(&options.all)->default_value(true),
         "showing each factorials until 'n!' (default: true)")
        ;

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

    if (vm.count("help")) {
        std::cout << description << std::endl;
        return false;
    }

    return true;
}

/// Simple example demonstrating how to generate factorials.
///
/// @param argc number of parameters
/// @param argv array of parameters
/// @return 0 when succeeded, 1 when failed or when used the help
int main(int argc, char** argv) {
    std::cout << "factorial tool (version " << VERSION << ")" << std::endl;

    Options options;
    // parsing command line options
    if (!parse(argc, argv, options)) {
        return 1;
    }

    // registering implementations
    math::big_integer_configurator bic;
    bic.configure();

    math::big_integer bi = 1;
    std::cout << options.max_n << "!" << std::endl << std::endl;

    std::vector<math::big_integer> results;

    const auto duration = performance::measure<std::milli>([&options, &bi, &results]() {
        for (auto n = static_cast<uint64_t>(2); n <= options.max_n; ++n) {
            bi *= math::big_integer(n);
            if (options.all) {
                results.push_back(bi);
            }
        }
    });

    if (!options.all) {
        results.push_back(bi);
    }

    for (const auto& result: results) {
        std::cout << result.to_string() << std::endl;
    }

    std::cout << std::endl;
    std::cout << " ... " << bi.size() << " digits." << std::endl;
    std::cout << " ... Calculation only took " << duration << "ms." << std::endl;
    return 0;
}


#include <iostream>
#include <fstream>
#include <string>
#include <Eigen/Dense>
#include <conio.h>
#include<vector>
using namespace std;
using namespace Eigen;

MatrixXd Data(string fileToOpen)
{

    vector<double> matrixEntries;
    ifstream matrixDataFile(fileToOpen);
    string matrixRowString;
    string matrixEntry;

    int matrixRowNumber = 0;

    while (getline(matrixDataFile, matrixRowString))
    {
        stringstream matrixRowStringStream(matrixRowString);

        while (getline(matrixRowStringStream, matrixEntry, ','))
        {
            matrixEntries.push_back(stod(matrixEntry));
        }
        matrixRowNumber++;
    }

    return Map<Matrix<double, Dynamic, Dynamic, RowMajor>>(matrixEntries.data(), matrixRowNumber, matrixEntries.size() / matrixRowNumber);

}

void InvertirGaussJordan()
{
    MatrixXd m = Data("Texto.txt"), I(m.rows(),m.rows());
    int c = m.rows();
    //Se crea la matriz identidad
    for (int x = 0; x < c; x++)
    {
        for (int y = 0; y < c; y++)
        {
            I(x, y) = 0;
            if (x == y)
            {
                I(x, y) = 1;

            }
        }
    }
    cout << "Matriz inicial:\n " << m << endl;
    cout << "Matriz identidad:\n " << I << endl;
    cout << m.cols()<<endl;
    /*Para lograr que la diagonal de la matriz sea 1, se divide cada elemento de la diagonal por el mismo y por su
    fila correspondiente, igual con la matriz identidad.*/
    for (int x = 0; x < c; x++)
    {
        float v = m(x, x);

        for (int y = 0; y < c; y++)
        {

            m(x, y) = m(x, y)*(1/v);
            I(x, y) = I(x, y)*(1/v);
        }

        for (int j = 0; j < c; j++)
        {
            //verifico no estar en diagonal y empiezo a hacer GJ:
            if (x != j)
            {
                float  s = m(j, x);
                for (int k = 0; k < c; k++)
                {
                    m(j, k) = m(j, k) - (s * m(x, k));
                    I(j, k) = I(j, k) - (s * I(x, k));
                }

            }

        }
    }
    cout << "Inversa:\n " << I << endl;
    fstream archivo;
    archivo.open("Texto.txt", ios::app);
    if (archivo.is_open())
    {
        archivo <<"La inversa es: \n"<< I;
        archivo.close();
    }
}

int determinantecofactor(Matrix2d x)
{
    int resultado;
    resultado = x(0, 0) * x(1, 1) - x(0, 1) * (1, 0);
    return resultado;
}

void determinante(MatrixXd m)
{
    //intento de una funcion recursiva que calcula el determinante por cofactores.
     if (m.rows() == 2)
     {
         return determinantecofactor(m);
     }
    vector<int> f;

        for (int i = 0; i < m.rows(); i++)
        {
            for (int j = 0; j < m.rows(); j++)
            {
                for (int k = 0; k < m.rows(); k++)
                {
                    if ((j == i) && (k == 0))
                    {
                        continue;

                    }
                    MatrixXd m_l(m.rows() - 1, m.rows() - 1);
                    m_l(l,i) = m(j, k);
                    f.push_back(m(j, k));
                }

            }
        }

        cout << int(f.size()) << endl;
}
int main()
{

    InvertirGaussJordan();
    determinante(Data("Texto.txt"));
    return 0;

}


#ifndef STAN_MATH_PRIM_SCAL_FUN_LOG_DIFF_EXP_HPP
#define STAN_MATH_PRIM_SCAL_FUN_LOG_DIFF_EXP_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/fun/log1m_exp.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <boost/math/tools/promotion.hpp>

namespace stan {
namespace math {

/**
 * The natural logarithm of the difference of the natural exponentiation
 * of x and the natural exponentiation of y
 *
 * This function is only defined for x >= y
 *
 *
   \f[
   \mbox{log\_diff\_exp}(x, y) =
   \begin{cases}
     \textrm{NaN} & \mbox{if } x < y\\
     \ln(\exp(x)-\exp(y)) & \mbox{if } x \geq y \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{log\_diff\_exp}(x, y)}{\partial x} =
   \begin{cases}
     \textrm{NaN} & \mbox{if } x \leq y\\
     \frac{\exp(x)}{\exp(x)-\exp(y)} & \mbox{if } x > y \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{log\_diff\_exp}(x, y)}{\partial y} =
   \begin{cases}
     \textrm{NaN} & \mbox{if } x \leq y\\
     -\frac{\exp(y)}{\exp(x)-\exp(y)} & \mbox{if } x > y \\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN or } y = \textrm{NaN}
   \end{cases}
   \f]
 *
 */
template <typename T1, typename T2>
inline return_type_t<T1, T2> log_diff_exp(const T1 x, const T2 y) {
  if (x <= y)
    return (x < INFTY && x == y) ? NEGATIVE_INFTY : NOT_A_NUMBER;
  return x + log1m_exp(y - x);
}

}  // namespace math
}  // namespace stan

#endif


/**********************************************************************************************************************
This file is part of the Control Toolbox (https://adrlab.bitbucket.io/ct), copyright by ETH Zurich, Google Inc.
Licensed under Apache2 license (see LICENSE file in main directory)
**********************************************************************************************************************/

#pragma once

#include <Eigen/Dense>

namespace ct {
namespace models {
namespace quadrotor {

const double pi = 3.14159265;

// mass / inertia
const double mQ = 0.546;         // mass of quadcopter [ kg ]
const double Thxxyy = 2.32e-3;   // moment of inertia around x,y [ kg*m^2 ]
const double Thzz = 3e-4;        // moment of inertia around z [ kg*m^2 ]
const double arm_len = 0.175;    // length of quadcopter arm [ m ]
const double grav_const = 9.81;  // gravitational constant [ m/s^2 ]

const double f_hover = mQ * grav_const;

// Thrust parameters
const double kF = 6.17092e-8 * 3600 / (2 * pi * 2 * pi);  // rotor thrust coefficient [ N/rad^2 ]
const double kM = 1.3167e-9 * 3600 / (2 * pi * 2 * pi);   // rotor moment coefficient [ Nm/rad^2]
const double wmax = 7800.0 * 2 * pi / 60;                 // maximum rotor speed [ rad/s ]
const double wmin = 1200.0 * 2 * pi / 60;                 // minimum rotor speed [ rad/s ]
const double Fsat_min = kF * wmin * wmin;
const double Fsat_max = kF * wmax * wmax;

const Eigen::Vector4d kFs(kF, kF, kF, kF);
const Eigen::Vector4d kMs(kM, kM, kM, kM);

}  // namespace quadrotor
}  // namespace models
}  // namespace ct


//This code is an implementation of the Parallel ILU algorithm described in Chow and Patel (2015)
//"Fine-Grained Parallel Incomplete LU Factorization," SIAM J. Sci Comput., Vol. 37, No.2, C169-C193

//C++ and the Eigen library are used for sparse linear algebra, OpenMP is used for parallelization
//This implementation assumes the input of a square, symmetric, positive definite matrix
//Terminology used from paper: "ILU residual norm", "nonlinear residual norm"

//Developed by Marcos Botto Tornielli, May 2021

//####################################################################################################//
//######################## Parallel Incomplete LU Factorization ######################################//
//####################################################################################################//
#include <iostream>
#include <Eigen/Sparse>
#include <unsupported/Eigen/SparseExtra>
#include <iomanip>

int main()
{
    //dummy parallel region to use up the overhead from starting first region
#pragma omp parallel
    {
#pragma omp single
        std::cout << "This is thread #" << omp_get_thread_num() << std::endl;
    }

    //################################################################################################//
    //##################################### Matrix I/O ###############################################//
    //################################################################################################//

    //Define common Eigen objects to be used throughout the code
    typedef Eigen::SparseMatrix<double> SpMat;
    typedef Eigen::SparseMatrix<double,Eigen::RowMajor> SpMatRow;
    typedef Eigen::Triplet<double> T;

    //Define timing variables
    double t1,t2;

    //Load input matrix
    SpMat A;
    Eigen::loadMarket(A, "../input/Pres_Poisson/Pres_Poisson.mtx");

    //Matrix information as read from MatrixMarket file
    //Unknown loadMarket bug causes only lower triangular part of symmetric matrix to be read
    int rows = A.rows();
    int cols = A.cols();
    int nonzs = A.nonZeros();
    double norm = A.norm();
    bool compr = A.isCompressed();
    std::cout << "Matrix is compressed: " << compr << std::endl;
    std::cout << "Number of rows    : " << rows << std::endl;
    std::cout << "Number of columns : " << cols << std::endl;
    std::cout << "Number of nonzeros: " << nonzs << std::endl;
    std::cout << "Frobenius norm    : " << norm << std::endl << std::endl;

    //Workaround for loadMarket symmetry issue
    //Add A to its transpose; diagonal will be divided by 2 to compensate later
    SpMat A_t = A.transpose();
    A = A + A_t;
    //Matrix information for true A matrix
    rows = A.rows();
    cols = A.cols();
    nonzs = A.nonZeros();
    norm = A.norm();
    compr = A.isCompressed();
    std::cout << "Matrix is compressed: " << compr << std::endl;
    std::cout << "Number of rows    : " << rows << std::endl;
    std::cout << "Number of columns : " << cols << std::endl;
    std::cout << "Number of nonzeros: " << nonzs << std::endl;
    std::cout << "Frobenius norm    : " << norm << std::endl << std::endl;

    //################################################################################################//
    //################################ Diagonal Scaling of A #########################################//
    //################################################################################################//

    //Scale the diagonal down by 2 for loadMarket issue workaround
    //Compute values for diagonal scaling matrix D
    //Chow and Patel assume that the matrix used in the algorithm has been scaled to have unit diagonal

    std::vector<T> dTriplets;
    dTriplets.reserve(rows);
    for (int i=0; i<A.outerSize(); ++i)
    {
        for (Eigen::SparseMatrix<double>::InnerIterator it(A,i); it; ++it)
        {
            if (it.row() == it.col())
            {
                it.valueRef() = it.value()/2.0;
                double diag_entry = it.value();
                double scale_diag_entry = 1.0/sqrt(diag_entry);
                dTriplets.push_back(T(it.row(),it.row(),scale_diag_entry));
            }

        }
    }

    SpMat D(A.rows(),A.cols());
    D.setFromTriplets(dTriplets.begin(),dTriplets.end());

    //Scale A matrix for unit diagonal
    A = D*A*D;

    //################################################################################################//
    //##################### Define Sparsity Structure (not supported) ################################//
    //################################################################################################//

    //This section is included for potential future development
    //But the higher ILU Levels are not currently supported by the code (5/8/21)
    //Unless this support is added, the rest of the code assumes ILU(0) sparsity structure

    int ilu_level = 0;
    SpMat A_sparsity = A;

    for (int i=0; i<ilu_level; i++)
    {
        A_sparsity = A_sparsity*A;
    }

    //################################################################################################//
    //################### Construct Initial Guesses for L and U ######################################//
    //################################################################################################//

    //"Standard" initial guess used:
    //L guess is the strictly lower triangular part of A with an enforced unit diagonal
    //U guess is the upper triangular part of A (also has a unit diagonal because A does)

    std::vector<T> lTriplets;
    std::vector<T> uTriplets;

    lTriplets.reserve(((A.nonZeros() - A.rows())/2.0)+A.rows());
    uTriplets.reserve(((A.nonZeros() - A.rows())/2.0)+A.rows());

    for (int i=0; i<A.outerSize(); ++i)
    {
        for (Eigen::SparseMatrix<double>::InnerIterator it(A,i); it; ++it)
        {
            if (it.row() == it.col())
            {
                lTriplets.push_back(T(it.row(),it.col(),1.0));
            }

            if (it.row() > it.col())
            {
                lTriplets.push_back(T(it.row(),it.col(),it.value()));
            }else{
                uTriplets.push_back(T(it.row(),it.col(),it.value()));
            }

        }
    }

    SpMatRow L(A.rows(),A.cols());
    SpMat U(A.rows(),A.cols());
    L.setFromTriplets(lTriplets.begin(),lTriplets.end());
    U.setFromTriplets(uTriplets.begin(),uTriplets.end());

    //Calculate ILU residual norm for 0 sweeps
    SpMat resM = A - L*U;
    double ilu_res_norm = resM.norm();
    std::cout << "ILU residual norm,       0 sweeps: " << ilu_res_norm << std::endl;

    //Calculate nonlinear residual norm for 0 sweeps

    double nonl_res_norm = 0.0;

    t1 = omp_get_wtime();

#pragma omp parallel for reduction(+:nonl_res_norm) schedule(dynamic,8)
    for (int i=0; i<A.outerSize(); ++i)
    {
        for (Eigen::SparseMatrix<double>::InnerIterator it(A,i); it; ++it)
        {
            if (it.row() > it.col())
            {
                SpMat in_prod_mat = L.block(it.row(),0,1,it.col()+1) * U.block(0,it.col(),it.col()+1,1);
                double in_prod = in_prod_mat.coeffRef(0,0);
                nonl_res_norm = nonl_res_norm + abs(it.value() - in_prod);
            }else{
                SpMat in_prod_mat = L.block(it.row(),0,1,it.row()+1) * U.block(0,it.col(),it.row()+1,1);
                double in_prod = in_prod_mat.coeffRef(0,0);
                nonl_res_norm = nonl_res_norm + abs(it.value() - in_prod);
            }

        }
    }

    t2 = omp_get_wtime();

    std::cout << "Nonlinear residual norm, 0 sweeps: " << nonl_res_norm << std::endl;
    std::cout << "Time to compute (s)              : " << t2-t1 << std::endl << std::endl;

    //################################################################################################//
    //################################# MAIN ALGORITHM LOOP ##########################################//
    //################################################################################################//

    int n_sweeps = 5;

    for (int sweep=0; sweep<n_sweeps; sweep++)
    {
        t1 = omp_get_wtime();

#pragma omp parallel for schedule(dynamic,8)
        for (int i=0; i<A.outerSize(); ++i)
        {
            for (Eigen::SparseMatrix<double>::InnerIterator it(A,i); it; ++it)
            {
                if (it.row() > it.col())
                {
                    double div = 1.0/U.coeffRef(it.col(),it.col());
                    SpMat in_prod_mat = L.block(it.row(),0,1,it.col()) * U.block(0,it.col(),it.col(),1);
                    double in_prod = in_prod_mat.coeffRef(0,0);
                    L.coeffRef(it.row(),it.col()) = (it.value() - in_prod) * div;
                }else{
                    SpMat in_prod_mat = L.block(it.row(),0,1,it.row()) * U.block(0,it.col(),it.row(),1);
                    double in_prod = in_prod_mat.coeffRef(0,0);
                    U.coeffRef(it.row(),it.col()) = it.value() - in_prod;
                }

            }
        }

        t2 = omp_get_wtime();
        std::cout << "Time to compute sweep " << sweep+1 << " (s)      : " << t2-t1 << std::endl << std::endl;

        //Calculate ILU residual norm for current number of sweeps
        resM = A - L*U;
        ilu_res_norm = resM.norm();
        std::cout << "ILU residual norm,       " << sweep+1 << " sweeps: " << ilu_res_norm << std::endl;

        //Calculate nonlinear residual norm for current number of sweeps
        nonl_res_norm = 0.0;

        t1 = omp_get_wtime();

#pragma omp parallel for reduction(+:nonl_res_norm) schedule(dynamic,8)
        for (int i=0; i<A.outerSize(); ++i)
        {
            for (Eigen::SparseMatrix<double>::InnerIterator it(A,i); it; ++it)
            {
                if (it.row() > it.col())
                {
                    SpMat in_prod_mat = L.block(it.row(),0,1,it.col()+1) * U.block(0,it.col(),it.col()+1,1);
                    double in_prod = in_prod_mat.coeffRef(0,0);
                    nonl_res_norm = nonl_res_norm + abs(it.value() - in_prod);
                }else{
                    SpMat in_prod_mat = L.block(it.row(),0,1,it.row()+1) * U.block(0,it.col(),it.row()+1,1);
                    double in_prod = in_prod_mat.coeffRef(0,0);
                    nonl_res_norm = nonl_res_norm + abs(it.value() - in_prod);
                }

            }
        }

        t2 = omp_get_wtime();

        std::cout << "Nonlinear residual norm, " << sweep+1 << " sweeps: " << nonl_res_norm << std::endl;
        std::cout << "Time to compute (s)              : " << t2-t1 << std::endl << std::endl <<std::endl;

    }

    return 0;
}
//####################################################################################################//
//####################################################################################################//
//####################################################################################################//


#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/math/tools/solve.hpp>
#include <iostream>
#include <iomanip>
#include <regex>
#include <omp.h>
#include "../lib/prim2d.h"
#include "../lib/de2d.h"

#define ub  boost::numeric::ublas

#define DEBUG 2

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

    if( !argv[1] )
    {
        std::cout << "set the input file name\n";
        exit(1);
    }
    std::string fileName0(argv[1]);

    std::vector<Segm2D> sigma_t;
    sigma_t.reserve(1000);

    load_border(sigma_t, fileName0);
    size_t n = sigma_t.size();
    #if DEBUG > 1
       std::cout << "\033[31;1mn = " << n << "\033[0m\n";
    #endif

    bool isMove = true;
    int cycle = 0;
    double t = 0.0;
    double dt = 0.01;
    const double T = 5.;
    const double lambda = 0.5;
    const double alpha = 0.2;
    const Vector2D rM1 = Vector2D(2.5,0.0);
    const double q1 = -M_PI;
    const double T0 = 1.0;
    const double VEps = 0.1;
    const size_t max_cycle = 20;

    ub::matrix<double> A(n,n);
    ub::vector<double> f(n);
    ub::vector<double> g(n);

    for(;cycle<max_cycle&&isMove;++cycle)
    {

        // ***********   stage 1 *****************//

        double ts1 = omp_get_wtime();
        #pragma omp parallel for
        for(size_t i=0; i<n; ++i)
        {
            Vector2D rM = (sigma_t[i].A + sigma_t[i].B)/2.0;
            for(size_t j=0; j<n; ++j)
            {
                if(i!=j)
                {
                    Vector2D rN = 0.5*(sigma_t[j].A + sigma_t[j].B );
                    Vector2D nN = normal(sigma_t[j]);
                    A(i,j)=-2.0*lambda*Omega(rM,rN,nN)*dl(sigma_t[j]);
                }
                else A(i,j)=1.0;
            }
            f(i)=2.0*lambda*phi0(rM,q1,rM1)+2.0*alpha*rM.y;
        }
        double te1 = omp_get_wtime();
        std::cout << "\t\033[33mstage 1: "
                  << std::fixed << std::showpoint<< std::setprecision(10)
                  << te1-ts1 << " sec.\033[0m";

        // ***********   stage 2 *****************//

        double ts2 = omp_get_wtime();
        g = boost::math::tools::solve(A,f);
        double te2 = omp_get_wtime();
        std::cout << "\t\033[34mstage 2: "
                  << std::fixed << std::showpoint<< std::setprecision(5)
                  << te2-ts2 << " sec.\033[0m";

        // ***********   stage 3 *****************//

        std::vector<Vector2D> vA(n), vB(n);

        double ts3 = omp_get_wtime();
        #pragma omp parallel for
        for(size_t i=0; i<n; ++i){
            Vector2D rMA = sigma_t[i].A;
            vA[i] = v0(rMA,q1,rM1);
            for(size_t j=0; j<n; ++j)
                vA[i] += g(j)*vSegmTheta(rMA,sigma_t[j],VEps);
        }// for_i

        #pragma omp parallel for
        for(size_t i=0; i<n; ++i){
            sigma_t[i].A += vA[i]*dt;
            sigma_t[(i+1)%n].B = sigma_t[i].A;

        }// for_i

        double te3 = omp_get_wtime();
        std::cout << "\t\033[35mstage 3: "
                  << std::fixed << std::showpoint<< std::setprecision(10)
                  << te3-ts3 << " sec. \033[0m\n";

        t+=dt/T0;

        #if DEBUG > 1
        for( size_t k=1; k<5; ++k)
            if(cycle==(k*(max_cycle-1)/5))
            {
                std::stringstream ss;
                ss << k;
                std::string suffix;
                ss >> suffix;

                std::string outFileName = std::regex_replace(
                    fileName0,
                    std::regex("0"),
                    suffix
                );
                std::cout << "\033[31;1mcycle=" << std::setw(4) << cycle
                          << "\tsave " << outFileName
                          << "\t\tt = " << t
                          << "\033[0m\n";
                save_border(sigma_t, outFileName);
            }
        #endif

        // set your conditions for the variable isMove here:
        // if ( u cond. )  isMove = false;

    } // cycle

    std::cout <<  "\033[32;1msimulation time T = " << T << "\033[0m\n";
    std::string outFileName = std::regex_replace(
        fileName0,
        std::regex("0"),
        "_end"
    );
    save_border(sigma_t, outFileName);

}//main


#define _USE_MATH_DEFINES

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

namespace plt = matplotlibcpp;

Eigen::ArrayXd fun(const Eigen::ArrayXd& t)
{
    using Eigen::cos;
    using Eigen::exp;
    using Eigen::sin;
    return 0.0981 * cos(0.1 * t - 0.007845) - exp(-0.3999 * t) * (0.0981 * cos(3.169 * t) + 0.0124 * sin(3.169 * t));
}

int main()
{
    Eigen::VectorXd x = Eigen::VectorXd::LinSpaced(100, 0, 10);
    Eigen::VectorXd y = fun(x.array());
    plt::stl::plot(x.data(), x.data() + x.size(), y.data(),
                   {{"label", "Eigen VectorXd"}, {"marker", "o"}, {"markersize", "5"}, {"markerfacecolor", "#3efab0"}});
    plt::legend();
    plt::show();
}


#include <math.h>
#include <float.h>

#include <Eigen/Sparse>

#include "HarmonicMap.h"

#ifndef M_PI
#define M_PI 3.141592653589793238462643383279
#endif

void MeshLib::CHarmonicMap::set_mesh(CHarmonicMapMesh* pMesh)
{
    m_pMesh = pMesh;

    // 1. compute the weights of edges
    _calculate_edge_weight();

    // 2. map the boundary to unit circle
    _set_boundary();

    // 3. initialize the map of interior vertices to (0, 0)
    using M = CHarmonicMapMesh;
    for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
    {
        M::CVertex* pV = *viter;
        if (pV->boundary())
            continue;
		//insert your code here
        pV->uv() = CPoint2(0, 0);
    }
}

double MeshLib::CHarmonicMap::step_one()
{
    if (!m_pMesh)
    {
        std::cerr << "Should set mesh first!" << std::endl;
        return DBL_MAX;
    }

    using M = CHarmonicMapMesh;

    // move each interior vertex to its weighted center of neighbors
    double max_error = -DBL_MAX;
    for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
    {
        M::CVertex* pV = *viter;
        if (pV->boundary())
            continue;

        double sw = 0;
        CPoint2 suv(0, 0);
        for (M::VertexVertexIterator vviter(pV); !vviter.end(); vviter++)
        {
            M::CVertex* pW = *vviter;
            M::CEdge* pE = m_pMesh->vertexEdge(pV, pW);
			//insert your code here
            suv += pW->uv() * pE->weight();
            sw += pE->weight();
        }
        suv /= sw;

        double error = (pV->uv() - suv).norm();
        max_error = (error > max_error) ? error : max_error;
        pV->uv() = suv;
    }

    printf("Current max error is %g\n", max_error);
    return max_error;
}

void MeshLib::CHarmonicMap::iterative_map(double epsilon)
{
    if (!m_pMesh)
    {
        std::cerr << "Should set mesh first!" << std::endl;
        return;
    }

    using M = CHarmonicMapMesh;

    // take steps until it converges.
    while (true)
    {
        double error = this->step_one();
        if (error < epsilon)
            break;
    }
}

void MeshLib::CHarmonicMap::map()
{
    if (!m_pMesh)
    {
        std::cerr << "Should set mesh first!" << std::endl;
        return;
    }

    using M = CHarmonicMapMesh;

    // 1. Initialize
    int vid = 0;  // interior vertex id
    int bid = 0;  // boundary vertex id
    for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
    {
        M::CVertex* pV = *viter;

        if (pV->boundary())
            pV->idx() = bid++;
        else
            pV->idx() = vid++;
    }

    int interior_vertices = vid;
    int boundary_vertices = bid;

    // 2. Set the matrix A and B
    std::vector<Eigen::Triplet<double>> A_coefficients;
    std::vector<Eigen::Triplet<double>> B_coefficients;

    for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
    {
        M::CVertex* pV = *viter;
        if (pV->boundary())
            continue;
        int vid = pV->idx();

        double sw = 0;
        for (M::VertexVertexIterator witer(pV); !witer.end(); ++witer)
        {
            M::CVertex* pW = *witer;
            int wid = pW->idx();

            M::CEdge* e = m_pMesh->vertexEdge(pV, pW);
            double w = e->weight();

			//insert your code here
			//construct one element of the matrix A and B, using
            sw += w;
			//there push_back the triplet to A or B coefficients
            if (pW->boundary())
            {
                B_coefficients.push_back(Eigen::Triplet<double>(vid, wid, w));
            }
            else
            {
                A_coefficients.push_back(Eigen::Triplet<double>(vid, wid, -1 * w));
            }
        }
		//insert the diagonal element
        A_coefficients.push_back(Eigen::Triplet<double>(vid, vid, sw));

    }

    Eigen::SparseMatrix<double> A(interior_vertices, interior_vertices);
    A.setZero();
    Eigen::SparseMatrix<double> B(interior_vertices, boundary_vertices);
    B.setZero();
    A.setFromTriplets(A_coefficients.begin(), A_coefficients.end());
    B.setFromTriplets(B_coefficients.begin(), B_coefficients.end());

    // 3. Solve the equations
    Eigen::ConjugateGradient<Eigen::SparseMatrix<double>> solver;
    std::cerr << "Eigen Decomposition" << std::endl;
    solver.compute(A);
    std::cerr << "Eigen Decomposition Finished" << std::endl;

    if (solver.info() != Eigen::Success)
    {
        std::cerr << "Waring: Eigen decomposition failed" << std::endl;
    }

    for (int k = 0; k < 2; k++)
    {
        Eigen::VectorXd b(boundary_vertices);
        // set boundary constraints vector b
        for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
        {
            M::CVertex* pV = *viter;
            if (!pV->boundary())
                continue;
            int id = pV->idx();
            b(id) = pV->uv()[k];
        }

        Eigen::VectorXd c(interior_vertices);
        c = B * b;

        Eigen::VectorXd x = solver.solve(c); // Ax=c
        if (solver.info() != Eigen::Success)
        {
            std::cerr << "Waring: Eigen decomposition failed" << std::endl;
        }

        // set the images of the harmonic map to interior vertices
        for (M::MeshVertexIterator viter(m_pMesh); !viter.end(); ++viter)
        {
            M::CVertex* pV = *viter;
            if (pV->boundary())
                continue;
            int id = pV->idx();
            pV->uv()[k] = x(id);
        }
    }
}

void MeshLib::CHarmonicMap::_calculate_edge_weight()
{
    using M = CHarmonicMapMesh;

    // 1. compute edge length
    for (M::MeshEdgeIterator eiter(m_pMesh); !eiter.end(); ++eiter)
    {
        M::CEdge* pE = *eiter;
        M::CVertex* v1 = m_pMesh->edgeVertex1(pE);
        M::CVertex* v2 = m_pMesh->edgeVertex2(pE);
        pE->length() = (v1->point() - v2->point()).norm();
    }

    // 2. compute corner angle
    for (M::MeshFaceIterator fiter(m_pMesh); !fiter.end(); ++fiter)
    {
        M::CFace* pF = *fiter;
        M::CHalfEdge* pH[3];
		//insert your code here
        int i = 0;
        for (M::FaceHalfedgeIterator fhiter(pF); !fhiter.end(); ++fhiter)
        {
            pH[i] = *fhiter;
            i++;
            assert(i < 4);
        }
        assert(i == 3);
        assert(pH[0]->target() == pH[1]->source());
        assert(pH[1]->target() == pH[2]->source());
        assert(pH[2]->target() == pH[0]->source());
		//use inverse cosine law to compute the corner angles
        pH[0]->angle() = _inverse_cosine_law(static_cast<CHarmonicMapEdge *>(pH[1]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[2]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[0]->edge())->length());
        pH[1]->angle() = _inverse_cosine_law(static_cast<CHarmonicMapEdge*>(pH[0]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[2]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[1]->edge())->length());
        pH[2]->angle() = _inverse_cosine_law(static_cast<CHarmonicMapEdge*>(pH[1]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[0]->edge())->length(), static_cast<CHarmonicMapEdge*>(pH[2]->edge())->length());
    }

    // 3. compute edge weight
    for (M::MeshEdgeIterator eiter(m_pMesh); !eiter.end(); ++eiter)
    {
        M::CEdge* pE = *eiter;
		//insert your code here
        if (pE->halfedge(0) != NULL)
        {
            pE->weight() += std::tan(M_PI / 2 - static_cast<CHarmonicMapHalfEdge*>(pE->halfedge(0))->angle());
        }
        if (pE->halfedge(1) != NULL)
        {
            pE->weight() += std::tan(M_PI / 2 - static_cast<CHarmonicMapHalfEdge*>(pE->halfedge(1))->angle());
        }
		//set cotangent edge weight
    }
}

void MeshLib::CHarmonicMap::_set_boundary()
{
    using M = CHarmonicMapMesh;

    // 1. get the boundary half edge loop
    M::CBoundary boundary(m_pMesh);
    std::vector<M::CLoop*>& pLs = boundary.loops();
    if (pLs.size() != 1)
    {
        std::cerr << "Only topological disk accepted!" << std::endl;
        exit(EXIT_FAILURE);
    }
    M::CLoop* pL = pLs[0];
    std::list<M::CHalfEdge*>& pHs = pL->halfedges();

    // 2. compute the total length of the boundary
    double sum = 0.0;
    std::list<M::CHalfEdge*>::iterator it;
    for (it = pHs.begin(); it != pHs.end(); ++it)
    {
        M::CHalfEdge* pH = *it;
        sum += m_pMesh->halfedgeEdge(pH)->length();
    }

    // 3. parameterize the boundary using arc length parameter
    double len = 0.0;
    for (it = pHs.begin(); it != pHs.end(); ++it)
    {
        M::CHalfEdge* pH = *it;
        M::CVertex* pV = m_pMesh->halfedgeVertex(pH);

        len += m_pMesh->halfedgeEdge(pH)->length();
        double angle = len / sum * 2.0 * M_PI;
        pV->uv() = CPoint2(cos(angle), sin(angle));
    }
}

double MeshLib::CHarmonicMap::_inverse_cosine_law(double a, double b, double c)
{
    double cs = (a * a + b * b - c * c) / (2.0 * a * b);
    assert(cs <= 1.0 && cs >= -1.0);
    return std::acos(cs);
}


/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*
 Copyright (C) 2010 Sebastian Schlenkrich

*/

#ifndef quantlib_gausslobatto_hpp
#define quantlib_gausslobatto_hpp

#include <ql/types.hpp>
#include <boost/function.hpp>

namespace TemplateAuxilliaries {

    //! Template for Gauss-Lobatto integration, see gausslobattointegral.hpp/.cpp
    template <class Type>
    class GaussLobatto {
    private:
        //! local types
        typedef double Real;
        //! attributes
        mutable size_t maxEvaluations_;
        mutable Type absAccuracy_;
        mutable Type relAccuracy_;
        mutable Type absError_;
        mutable size_t evaluations_;
        const bool useConvergenceEstimate_;
        //! constants
        const static double alpha_, beta_, x1_, x2_, x3_;
        //! specific integration routines
        Type calculateAbsTolerance(const boost::function<Type (Type)>& f, Type a, Type b) const;
        Type adaptivGaussLobattoStep(const boost::function<Type (Type)>& f, Type a, Type b, Type fa, Type fb, Type acc) const;
    public:
        //! constructor
        GaussLobatto( size_t maxEvaluations,
                      Type absAccuracy,
                      Type relAccuracy = 0,
                      bool useConvergenceEstimate = true )
            : maxEvaluations_(maxEvaluations), absAccuracy_(absAccuracy), relAccuracy_(relAccuracy),
              absError_(0), evaluations_(0), useConvergenceEstimate_(useConvergenceEstimate) {}
        //! inspectors
        Type absoluteAccuracy() const { return absAccuracy_;      }
        Type absoluteError()    const { return absError_;         }
        size_t maxEvaluations()   const { return maxEvaluations_;   }
        size_t evaluations()      const { return evaluations_;      }
        //! modifiers
        void setNumberOfEvaluations(size_t number)         const { evaluations_ = number; }
        void increaseNumberOfEvaluations(size_t increase)  const { evaluations_ += increase; }
        //! integrate function interface
        Type integrate(const boost::function<Type (Type)>& f, Type a, Type b) const {
            //setNumberOfEvaluations(0);
            const Type calcAbsTolerance = calculateAbsTolerance(f, a, b);
            //increaseNumberOfEvaluations(2);
            return adaptivGaussLobattoStep(f, a, b, f(a), f(b), calcAbsTolerance);
        }
    };

    template <class Type> const double GaussLobatto<Type>::alpha_ = std::sqrt(2.0/3.0);
    template <class Type> const double GaussLobatto<Type>::beta_  = 1.0/std::sqrt(5.0);
    template <class Type> const double GaussLobatto<Type>::x1_    = 0.94288241569547971906;
    template <class Type> const double GaussLobatto<Type>::x2_    = 0.64185334234578130578;
    template <class Type> const double GaussLobatto<Type>::x3_    = 0.23638319966214988028;

    template <class Type> Type
    GaussLobatto<Type>::calculateAbsTolerance( const boost::function<Type (Type)>& f, Type a, Type b) const {
        Type relTol = (relAccuracy_ > QL_EPSILON) ? relAccuracy_ : QL_EPSILON;

        const Type m = (a+b)/2;
        const Type h = (b-a)/2;
        const Type y1 = f(a);
        const Type y3 = f(m-alpha_*h);
        const Type y5 = f(m-beta_*h);
        const Type y7 = f(m);
        const Type y9 = f(m+beta_*h);
        const Type y11= f(m+alpha_*h);
        const Type y13= f(b);

        Type acc=h*(0.0158271919734801831*(y1+y13)
                  +0.0942738402188500455*(f(m-x1_*h)+f(m+x1_*h))
                  +0.1550719873365853963*(y3+y11)
                  +0.1888215739601824544*(f(m-x2_*h)+ f(m+x2_*h))
                  +0.1997734052268585268*(y5+y9)
                  +0.2249264653333395270*(f(m-x3_*h)+f(m+x3_*h))
                  +0.2426110719014077338*y7);

        increaseNumberOfEvaluations(13);
        QL_REQUIRE(acc != 0.0, "can not calculate absolute accuracy from "
                               "relative accuracy");

        Type r = 1.0;
        if (useConvergenceEstimate_) {
            const Type integral2 = (h/6)*(y1+y13+5*(y5+y9));
            const Type integral1 = (h/1470)*(77*(y1+y13)+432*(y3+y11)+
                                             625*(y5+y9)+672*y7);

            if (fabs(integral2-acc) != 0.0)
                r = fabs(integral1-acc)/fabs(integral2-acc);
            if (r == 0.0 || r > 1.0)
                r = 1.0;
        }

        if (relAccuracy_ != 0)
            return  ((absoluteAccuracy() < acc*relTol) ? absoluteAccuracy() : acc*relTol)/(r*QL_EPSILON);
                    //min(absoluteAccuracy(), acc*relTol)/(r*QL_EPSILON);
        else {
            return absoluteAccuracy()/(r*QL_EPSILON);
        }
    }

    template <class Type> Type
    GaussLobatto<Type>::adaptivGaussLobattoStep(const boost::function<Type (Type)>& f, Type a, Type b, Type fa, Type fb, Type acc) const {
        QL_REQUIRE(evaluations() < maxEvaluations(),
                   "max number of iterations reached");

        const Type h=(b-a)/2;
        const Type m=(a+b)/2;

        const Type mll=m-alpha_*h;
        const Type ml =m-beta_*h;
        const Type mr =m+beta_*h;
        const Type mrr=m+alpha_*h;

        const Type fmll= f(mll);
        const Type fml = f(ml);
        const Type fm  = f(m);
        const Type fmr = f(mr);
        const Type fmrr= f(mrr);
        increaseNumberOfEvaluations(5);

        const Type integral2=(h/6)*(fa+fb+5*(fml+fmr));
        const Type integral1=(h/1470)*(77*(fa+fb)
                                       +432*(fmll+fmrr)+625*(fml+fmr)+672*fm);

        // avoid 80 bit logic on x86 cpu
        Type dist = acc + (integral1-integral2);
        if(dist==acc || mll<=a || b<=mrr) {
            QL_REQUIRE(m>a && b>m,"Interval contains no more machine number");
            return integral1;
        }
        else {
            return  adaptivGaussLobattoStep(f,a,mll,fa,fmll,acc)
                  + adaptivGaussLobattoStep(f,mll,ml,fmll,fml,acc)
                  + adaptivGaussLobattoStep(f,ml,m,fml,fm,acc)
                  + adaptivGaussLobattoStep(f,m,mr,fm,fmr,acc)
                  + adaptivGaussLobattoStep(f,mr,mrr,fmr,fmrr,acc)
                  + adaptivGaussLobattoStep(f,mrr,b,fmrr,fb,acc);
        }
    }

}

#endif  /* ifndef quantlib_gausslobatto_hpp */


//          Copyright Gavin Band 2008 - 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <math.h>
#include <cassert>
#include <vector>
#include <algorithm>
#include <Eigen/Core>
#include "metro/log_sum_exp.hpp"

namespace metro {
	template<>
	double log_sum_exp( std::vector< double > const& data ) {
		if( data.size() == 0 ) {
			return -std::numeric_limits< double >::infinity() ;
		}
		std::vector< double >::const_iterator max_i = std::max_element( data.begin(), data.end() ) ;
		double const max_value = *max_i ;
		if( max_value == -std::numeric_limits< double >::infinity() ) {
			return max_value ;
		}
		// exponentiate
		double result = max_value ;
		for( std::size_t i = 0; i < data.size(); ++i ) {
			result += std::exp(data[i] - max_value) ;
		}
		return max_value + std::log( result ) ;
	}

	void rowwise_log_sum_exp( Eigen::MatrixXd const& data, Eigen::VectorXd* result ) {
		assert( result ) ;
		assert( result->size() == data.rows() ) ;

		for( int i = 0; i < result->size(); ++i ) {
			(*result)(i) = log_sum_exp( data.row(i) ) ;
		}
	}
	void rowwise_log_sum_exp( Eigen::MatrixXd const& data, Eigen::MatrixXd const& nonmissingness, Eigen::VectorXd* result ) {
		assert( result ) ;
		assert( result->size() == data.rows() ) ;
		assert( data.rows() == nonmissingness.rows() ) ;
		assert( data.cols() == nonmissingness.cols() ) ;

		for( int i = 0; i < result->size(); ++i ) {
			(*result)(i) = log_sum_exp( data.row(i), nonmissingness.row(i) ) ;
		}
	}
}


#define _LIE_ALGEBRA_

#include <iostream>
#include <vector>
#include <armadillo>
#include <cmath>
#include <algorithm>

#ifdef _WEIGHTED_MAT_
#else
#include "weightedMat.hpp"
#endif

using arma::cx_mat;
using arma::kron;

using std::vector;
using std::cout;
using std::endl;

class LieAlgebra
{

  public:

    LieAlgebra(int n, double penalty)
    {
      basisGenerator(n, penalty, lieBasis);
    }

    ~LieAlgebra();

    vector<weightedMat> lieBasis;

    struct byCost
    {
        bool operator()(weightedMat const &a, weightedMat const &b)
        {
          		return a.cost < b.cost;
        }
    };

  private:

    cx_double imagI = cx_double(0.0, 1.0);

    void generatorLoop(int depth,
              vector<int> & indices,
              vector<int> & maxIndex,
              vector<cx_mat>& Paulis,
              vector<weightedMat>& lieBasis,
              double penalty
              )
    {
      if (depth>0){
         for(int i = 0; i < maxIndex[depth-1]; ++i){
            indices[depth-1] = i;
            generatorLoop(depth-1, indices, maxIndex, Paulis, lieBasis, penalty);
         }
      }
      else
      {
          // indices of tensor product
          //cout << "indices : ";
          int numNonZeros = 0;
          weightedMat temp;
          temp.lieMat = Paulis[indices[0]];

          for(int r = 0; r < indices.size(); ++r)
          {
            if(indices[r] != 0)
            {
              ++numNonZeros;
            }
            //cout << indices[r] <<" ";
          }

          if(numNonZeros < 3 )
          {
            temp.cost = 1;
          }
          else
          {
            temp.cost = penalty;
          }

          //make kronecker products
          for(int r = 1; r < indices.size(); ++r)
          {
            temp.lieMat = kron(temp.lieMat, Paulis[indices[r]]);
          }

          temp.lieMat *= imagI;

          //sub riemannian case
          lieBasis.push_back(temp);

       }
    }

    //n is 2^n in SU(2^n)
    void basisGenerator(int n, double penalty, vector<weightedMat>& lieBasis)
    {

      vector<cx_mat> Paulis;
      Paulis.reserve(4);

      Paulis[0] = eye<cx_mat>(2,2);
      Paulis[1] = { {0.0,0.0}, {1.0,0.0}, {1.0,0.0}, {0.0,0.0} };
      Paulis[2] = { {0.0,0.0}, {0.0,1.0}, {0.0,-1.0}, {0.0,0.0} };
      Paulis[3] = { {1.0,0.0}, {0.0,0.0}, {0.0,0.0}, {-1.0,0.0} };

      for(int s = 1; s < 4; ++s)
      {
        Paulis[s].reshape(2,2);
      }

      vector<int> indices(n,0);
      vector<int> maxIndex;

      for(int i=0; i<n; ++i)
      {
        maxIndex.push_back(4);
      }

      generatorLoop(indices.size(),indices, maxIndex, Paulis, lieBasis, penalty);

      //for SU remove the identity product I otimes I .... otimes I
      lieBasis.erase(lieBasis.begin());
      std::sort(lieBasis.begin(), lieBasis.end(), byCost());

      cout << "number of basis elements : " << lieBasis.size() << endl;
      for(int i=0; i< lieBasis.size(); ++i)
      {
        cout << "basis element :" << i << " with cost :" << lieBasis[i].cost << endl << lieBasis[i].lieMat << endl;
      }
    }
};


#include "config.hpp"
#include "include/common.hpp"
#include "include/pi.hpp"
#include <boost/mpi.hpp>
#include <boost/program_options.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iomanip>
#include <iostream>
#include <string>

namespace mpi = boost::mpi;
namespace po = boost::program_options;
namespace mp = boost::multiprecision;

using number = mp::number<mp::cpp_dec_float<10000>>;
constexpr int ROOT = 0;

namespace mpi_pi {

int main(int argc, char **argv) {
  mpi::environment env(argc, argv, false);
  mpi::communicator world;

  config::Configuration config;
  po::options_description description("options");
  if (world.rank() == ROOT) {
    description.add_options()("help,h", "print help message");
    description.add_options()(
        "method,m", po::value<std::string>()->default_value("area_integral"),
        "method to calculate pi");
    description.add_options()("terms,t",
                              po::value<std::size_t>()->default_value(1000),
                              "terms number to calculate");

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

    if (vm.count("help"))
      config.show_help = true;
    if (vm.count("method"))
      config.method = vm["method"].as<std::string>();
    if (vm.count("terms"))
      config.terms = vm["terms"].as<std::size_t>();
  }

  mpi::broadcast(world, config, ROOT);

  if (config.show_help) {
    if (world.rank() == ROOT) {
      std::cout << description << std::endl;
    }
    return 0; // all processes exit
  }

  number result;
  if (config.method == "area_integral") {
    result = area_integral::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "power_series") {
    result = power_series::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "improved_power_series") {
    result = improved_power_series::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "monte_carlo") {
    result = monte_carlo::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "monte_carlo_integral") {
    result = monte_carlo_integral::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "random_integral") {
    result = random_integral::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "borwein1987") {
    result = borwein1987::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "yasumasa2002") {
    result = yasumasa2002::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "chudnovsky") {
    result = chudnovsky::pi<number>(world, ROOT, config.terms);
  } else if (config.method == "bbp") {
    result = bbp::pi<number>(world, ROOT, config.terms);
  } else {
    std::cout << "invalid method \"" << config.method << "\"" << std::endl;
  }
  if (world.rank() == ROOT) {
    std::cout << std::setprecision(std::numeric_limits<number>::max_digits10)
              << result << std::endl;
  }
}

} // namespace mpi_pi

int main(int argc, char **argv) { return mpi_pi::main(argc, argv); }


/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright © 2020 Fragcolor Pte. Ltd. */

#ifndef CB_NO_BIGINT_BLOCKS

#include "math.h"
#include "shared.hpp"

#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/multiprecision/cpp_int.hpp>

using namespace boost::multiprecision;

namespace chainblocks {
namespace BigInt {
inline Var to_var(const cpp_int &bi, std::vector<uint8_t> &buffer) {
  buffer.clear();
  buffer.emplace_back(uint8_t(bi < 0));
  export_bits(bi, std::back_inserter(buffer), 8);
  return Var(&buffer.front(), buffer.size());
}

inline cpp_int from_var(const CBVar &op) {
  cpp_int bib;
  import_bits(bib, op.payload.bytesValue + 1,
              op.payload.bytesValue + op.payload.bytesSize);
  auto negative = bool(op.payload.bytesValue[0]);
  if (negative)
    bib *= -1;
  return bib;
}

struct ToBigInt {
  std::vector<uint8_t> _buffer;

  static inline Types InputTypes{CoreInfo::IntType, CoreInfo::FloatType,
                                 CoreInfo::StringType, CoreInfo::BytesType};
  static CBTypesInfo inputTypes() { return InputTypes; }
  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi;
    switch (input.valueType) {
    case Int: {
      bi = input.payload.intValue;
    } break;
    case Float: {
      bi = cpp_int(input.payload.floatValue);
    } break;
    case String: {
      bi = cpp_int(input.payload.stringValue);
    } break;
    case Bytes: {
      import_bits(bi, input.payload.bytesValue,
                  input.payload.bytesValue + input.payload.bytesSize);
    } break;
    default: {
      throw ActivationError("Invalid input type");
    }
    }
    return to_var(bi, _buffer);
  }
};

template <typename T>
struct BigIntBinaryOp : public ::chainblocks::Math::BinaryOperation<T> {
  std::deque<std::vector<uint8_t>> _buffers;
  size_t _offset{0};

  static inline Types BigIntInputTypes{
      {CoreInfo::BytesType, CoreInfo::BytesSeqType}};

  static CBTypesInfo inputTypes() { return BigIntInputTypes; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Any valid big integer(s) represented as bytes supported by "
                   "this operation.");
  }
  static CBTypesInfo outputTypes() { return BigIntInputTypes; }

  CBParametersInfo parameters() {
    static Parameters params{
        {"Operand",
         CBCCSTR("The bytes variable representing the operand"),
         {CoreInfo::BytesVarType, CoreInfo::BytesVarSeqType}}};
    return params;
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    _offset = 0;
    return ::chainblocks::Math::BinaryOperation<T>::activate(context, input);
  }
};

#define BIGINT_MATH_OP(__NAME__, __OP__)                                       \
  struct __NAME__ : public BigIntBinaryOp<__NAME__> {                          \
    void operator()(CBVar &output, const CBVar &input, const CBVar &operand,   \
                    void *pself) {                                             \
      auto self = reinterpret_cast<__NAME__ *>(pself);                         \
      std::vector<uint8_t> *buffer = nullptr;                                  \
      if (self->_buffers.size() <= _offset) {                                  \
        buffer = &self->_buffers.emplace_back();                               \
      } else {                                                                 \
        buffer = &self->_buffers[_offset];                                     \
      }                                                                        \
      cpp_int bia = from_var(input);                                           \
      cpp_int bib = from_var(operand);                                         \
      cpp_int bres = bia __OP__ bib;                                           \
      output = to_var(bres, *buffer);                                          \
      _offset++;                                                               \
    }                                                                          \
  };

struct BigOperandBase {
  std::vector<uint8_t> _buffer;

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }
  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBParametersInfo parameters() {
    static Parameters params{
        {"Operand",
         CBCCSTR("The bytes variable representing the operand"),
         {CoreInfo::BytesVarType}}};
    return params;
  }

  ParamVar _op{};

  void setParam(int index, const CBVar &value) { _op = value; }

  CBVar getParam(int index) { return _op; }

  void cleanup() { _op.cleanup(); }

  void warmup(CBContext *context) { _op.warmup(context); }

  const CBVar &getOperand() {
    CBVar &op = _op.get();
    if (op.valueType == None) {
      throw ActivationError("Operand is None, should be valid bigint bytes");
    }
    return op;
  }
};

struct RegOperandBase {
  std::vector<uint8_t> _buffer;

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }
  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBParametersInfo parameters() {
    static Parameters params{{"Operand",
                              CBCCSTR("The integer operand, can be a variable"),
                              {CoreInfo::IntType, CoreInfo::IntVarType}}};
    return params;
  }

  ParamVar _op{};

  void setParam(int index, const CBVar &value) { _op = value; }

  CBVar getParam(int index) { return _op; }

  void cleanup() { _op.cleanup(); }

  void warmup(CBContext *context) { _op.warmup(context); }

  const CBVar &getOperand() {
    CBVar &op = _op.get();
    if (op.valueType == None) {
      throw ActivationError("Operand is None, should be an integer");
    }
    return op;
  }
};

BIGINT_MATH_OP(Add, +);
BIGINT_MATH_OP(Subtract, -);
BIGINT_MATH_OP(Multiply, *);
BIGINT_MATH_OP(Divide, /);
BIGINT_MATH_OP(Xor, ^);
BIGINT_MATH_OP(And, &);
BIGINT_MATH_OP(Or, |);
BIGINT_MATH_OP(Mod, %);

#define BIGINT_LOGIC_OP(__NAME__, __OP__)                                      \
  struct __NAME__ : public BigOperandBase {                                    \
    static CBTypesInfo outputTypes() { return CoreInfo::BoolType; }            \
    static CBOptionalString outputHelp() {                                     \
      return CBCCSTR(                                                          \
          "A boolean value repesenting the result of the logic operation.");   \
    }                                                                          \
                                                                               \
    CBVar activate(CBContext *context, const CBVar &input) {                   \
      cpp_int bia = from_var(input);                                           \
      auto op = getOperand();                                                  \
      cpp_int bib = from_var(op);                                              \
      bool res = bia __OP__ bib;                                               \
      return Var(res);                                                         \
    }                                                                          \
  }

BIGINT_LOGIC_OP(Is, ==);
BIGINT_LOGIC_OP(IsNot, !=);
BIGINT_LOGIC_OP(IsMore, >);
BIGINT_LOGIC_OP(IsLess, <);
BIGINT_LOGIC_OP(IsMoreEqual, >=);
BIGINT_LOGIC_OP(IsLessEqual, <=);

#define BIGINT_BINARY_OP(__NAME__, __OP__)                                     \
  struct __NAME__ : public BigIntBinaryOp<__NAME__> {                          \
    void operator()(CBVar &output, const CBVar &input, const CBVar &operand,   \
                    void *pself) {                                             \
      auto self = reinterpret_cast<__NAME__ *>(pself);                         \
      std::vector<uint8_t> *buffer = nullptr;                                  \
      if (self->_buffers.size() <= _offset) {                                  \
        buffer = &self->_buffers.emplace_back();                               \
      } else {                                                                 \
        buffer = &self->_buffers[_offset];                                     \
      }                                                                        \
      cpp_int bia = from_var(input);                                           \
      cpp_int bib = from_var(operand);                                         \
      cpp_int bres = __OP__(bia, bib);                                         \
      output = to_var(bres, *buffer);                                          \
      _offset++;                                                               \
    }                                                                          \
  };

BIGINT_BINARY_OP(Min, std::min);
BIGINT_BINARY_OP(Max, std::max);

#define BIGINT_REG_BINARY_OP(__NAME__, __OP__)                                 \
  struct __NAME__ : public RegOperandBase {                                    \
    CBVar activate(CBContext *context, const CBVar &input) {                   \
      cpp_int bia = from_var(input);                                           \
      auto op = getOperand();                                                  \
      if (op.valueType != Int)                                                 \
        throw ActivationError("Pow operand should be an Int");                 \
      cpp_int bres = __OP__(bia, op.payload.intValue);                         \
      return to_var(bres, _buffer);                                            \
    }                                                                          \
  }

BIGINT_REG_BINARY_OP(Pow, pow);

#define BIGINT_UNARY_OP(__NAME__, __OP__)                                      \
  struct __NAME__ : public RegOperandBase {                                    \
    CBParametersInfo parameters() { return {}; }                               \
    CBVar activate(CBContext *context, const CBVar &input) {                   \
      cpp_int bia = from_var(input);                                           \
      cpp_int bres = __OP__(bia);                                              \
      return to_var(bres, _buffer);                                            \
    }                                                                          \
  }

BIGINT_UNARY_OP(Sqrt, sqrt);

struct ShiftBase {
  ParamVar _shift{Var(0)};

  void setParam(int index, const CBVar &value) { _shift = value; }

  CBVar getParam(int index) { return _shift; }

  void cleanup() { _shift.cleanup(); }

  void warmup(CBContext *context) { _shift.warmup(context); }
};

struct Shift : public ShiftBase {
  std::vector<uint8_t> _buffer;

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }
  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBParametersInfo parameters() {
    static Parameters params{
        {"By",
         CBCCSTR(
             "The shift is of the decimal point, i.e. of powers of ten, and is "
             "to the left if n is negative or to the right if n is positive."),
         {CoreInfo::IntType, CoreInfo::IntVarType}}};
    return params;
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi = from_var(input);
    cpp_dec_float_100 bf(bi);

    cpp_dec_float_100 bshift(_shift.get().payload.intValue);
    bshift = pow(cpp_dec_float_100(10), bshift);

    auto bres = cpp_int(bf * bshift);

    return to_var(bres, _buffer);
  }
};

struct ToFloat : public ShiftBase {
  static CBOptionalString help() {
    return CBCCSTR("Converts a big integer value to a floating point number.");
  }

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  static CBTypesInfo outputTypes() { return CoreInfo::FloatType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR(
        "Floating point number representation of the big integer value.");
  }

  CBParametersInfo parameters() {
    static Parameters params{
        {"ShiftedBy",
         CBCCSTR(
             "The shift is of the decimal point, i.e. of powers of ten, and is "
             "to the left if n is negative or to the right if n is positive."),
         {CoreInfo::IntType}}};
    return params;
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi = from_var(input);
    cpp_dec_float_100 bf(bi);

    cpp_dec_float_100 bshift(_shift.get().payload.intValue);
    bshift = pow(cpp_dec_float_100(10), bshift);

    auto bres = bf * bshift;

    return Var(bres.convert_to<double>());
  }
};

struct ToInt {
  static CBOptionalString help() {
    return CBCCSTR("Converts a big integer value to an integer.");
  }

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  static CBTypesInfo outputTypes() { return CoreInfo::IntType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Integer representation of the big integer value.");
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi = from_var(input);
    return Var(bi.convert_to<int64_t>());
  }
};

struct FromFloat : public ShiftBase {
  static CBOptionalString help() {
    return CBCCSTR("Converts a floating point number to a big integer.");
  }

  static CBTypesInfo inputTypes() { return CoreInfo::FloatType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Floating point number.");
  }

  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBParametersInfo parameters() {
    static Parameters params{
        {"ShiftedBy",
         CBCCSTR(
             "The shift is of the decimal point, i.e. of powers of ten, and is "
             "to the left if n is negative or to the right if n is positive."),
         {CoreInfo::IntType}}};
    return params;
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_dec_float_100 bi(input.payload.floatValue);

    cpp_dec_float_100 bshift(_shift.get().payload.intValue);
    bshift = pow(cpp_dec_float_100(10), bshift);

    auto bres = bi * bshift;
    cpp_int bo(bres);

    return to_var(bo, _buffer);
  }

private:
  std::vector<uint8_t> _buffer;
};

struct ToString {
  static CBOptionalString help() {
    return CBCCSTR("Converts the value to a string representation.");
  }

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }
  static CBTypesInfo outputTypes() { return CoreInfo::StringType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("String representation of the big integer value.");
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi = from_var(input);
    _buffer = bi.str();
    return Var(_buffer);
  }

private:
  std::string _buffer;
};

struct ToBytes {
  std::vector<uint8_t> _buffer;

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }
  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }

  CBParametersInfo parameters() {
    static Parameters params{{"Bits",
                              CBCCSTR("The desired amount of bits for the "
                                      "output or 0 for automatic packing."),
                              {CoreInfo::IntType}}};
    return params;
  }

  ParamVar _bits{Var(0)};

  void setParam(int index, const CBVar &value) { _bits = value; }

  CBVar getParam(int index) { return _bits; }

  void warmup(CBContext *context) { _bits.warmup(context); }
  void cleanup() { _bits.cleanup(); }

  CBVar activate(CBContext *context, const CBVar &input) {
    const auto bits = _bits.get().payload.intValue;
    if (bits <= 0) {
      CBVar fixedInput = input;
      fixedInput.payload.bytesValue++;
      fixedInput.payload.bytesSize--;
      return fixedInput;
    } else {
      cpp_int bi = from_var(input);
      const auto usedBits = msb(bi) + 1;
      if (usedBits > bits) {
        throw ActivationError(
            "The number of used bits is higher than the requested bits");
      }
      const auto padding = bits - usedBits;
      _buffer.clear();
      export_bits(bi, std::back_inserter(_buffer), 8);
      // this is because we are using little endianess
      _buffer.insert(_buffer.begin(), padding / 8, 0);
      return Var(_buffer);
    }
  }
};

struct ToHex {
  static CBOptionalString help() {
    return CBCCSTR("Converts the value to a hexadecimal representation.");
  }

  static inline Types toHexTypes{CoreInfo::IntType, CoreInfo::BytesType,
                                 CoreInfo::StringType};
  static CBTypesInfo inputTypes() { return toHexTypes; }

  static CBTypesInfo outputTypes() { return CoreInfo::StringType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Hexadecimal representation of the integer value.");
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    CBVar fixedInput = input;
    fixedInput.payload.bytesValue++;
    fixedInput.payload.bytesSize--;
    _stream.tryWriteHex(fixedInput);
    return Var(_stream.str());
  }

private:
  VarStringStream _stream;
};

struct Abs {
  static CBOptionalString help() {
    return CBCCSTR("Computes the absolute value of a big integer.");
  }

  static CBTypesInfo inputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString inputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  static CBTypesInfo outputTypes() { return CoreInfo::BytesType; }
  static CBOptionalString outputHelp() {
    return CBCCSTR("Big integer represented as bytes.");
  }

  CBVar activate(CBContext *context, const CBVar &input) {
    cpp_int bi = from_var(input);
    cpp_int abi = abs(bi);
    return to_var(abi, _buffer);
  }

private:
  std::vector<uint8_t> _buffer;
};

void registerBlocks() {
  REGISTER_CBLOCK("BigInt", ToBigInt);
  REGISTER_CBLOCK("BigInt.Add", Add);
  REGISTER_CBLOCK("BigInt.Subtract", Subtract);
  REGISTER_CBLOCK("BigInt.Multiply", Multiply);
  REGISTER_CBLOCK("BigInt.Divide", Divide);
  REGISTER_CBLOCK("BigInt.Xor", Xor);
  REGISTER_CBLOCK("BigInt.And", And);
  REGISTER_CBLOCK("BigInt.Or", Or);
  REGISTER_CBLOCK("BigInt.Mod", Mod);
  REGISTER_CBLOCK("BigInt.Shift", Shift);
  REGISTER_CBLOCK("BigInt.ToFloat", ToFloat);
  REGISTER_CBLOCK("BigInt.ToInt", ToInt);
  REGISTER_CBLOCK("BigInt.FromFloat", FromFloat);
  REGISTER_CBLOCK("BigInt.ToString", ToString);
  REGISTER_CBLOCK("BigInt.ToBytes", ToBytes);
  REGISTER_CBLOCK("BigInt.ToHex", ToHex);
  REGISTER_CBLOCK("BigInt.Is", Is);
  REGISTER_CBLOCK("BigInt.IsNot", IsNot);
  REGISTER_CBLOCK("BigInt.IsMore", IsMore);
  REGISTER_CBLOCK("BigInt.IsLess", IsLess);
  REGISTER_CBLOCK("BigInt.IsMoreEqual", IsMoreEqual);
  REGISTER_CBLOCK("BigInt.IsLessEqual", IsLessEqual);
  REGISTER_CBLOCK("BigInt.Min", Min);
  REGISTER_CBLOCK("BigInt.Max", Max);
  REGISTER_CBLOCK("BigInt.Pow", Pow);
  REGISTER_CBLOCK("BigInt.Abs", Abs);
  REGISTER_CBLOCK("BigInt.Sqrt", Sqrt);
}
} // namespace BigInt
} // namespace chainblocks

#else
namespace chainblocks {
namespace BigInt {
void registerBlocks() {}
} // namespace BigInt
} // namespace chainblocks
#endif


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

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_CONSTANT_DEGINRAD_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_DEGINRAD_HPP_INCLUDED

/*!
  @ingroup group-constant
  @defgroup constant-Deginrad Deginrad (function template)

  Generates the constant \f$\frac\pi{180}\f$.

  @headerref{<boost/simd/constant/deginrad.hpp>}

  @par Description

  1.  @code
      template<typename T> T Deginrad();
      @endcode

  2.  @code
      template<typename T> T Deginrad( boost::simd::as_<T> const& target );
      @endcode

  Generates the constant \f$\frac\pi{180}\f$ usable to convert degrees to radians.

  @par Parameters

  | Name                | Description                                                         |
  |--------------------:|:--------------------------------------------------------------------|
  | **target**          | a [placeholder](@ref type-as) value encapsulating the constant type |

  @par Return Value
  A value of type @c T that evaluates to `Pi<T>()/180`.

  @par Requirements
  - **T** models IEEEValue
**/

#include <boost/simd/constant/scalar/deginrad.hpp>
#include <boost/simd/constant/simd/deginrad.hpp>

#endif


// geometric_examples.cpp

// Copyright Paul A. Bristow 2010.

// 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)

// This file is written to be included from a Quickbook .qbk document.
// It can still be compiled by the C++ compiler, and run.
// Any output can also be added here as comment or included or pasted in elsewhere.
// Caution: this file contains Quickbook markup as well as code
// and comments: don't change any of the special comment markups!

// Examples of using the geometric distribution.

//[geometric_eg1_1
/*`
For this example, we will opt to #define two macros to control
the error and discrete handling policies.
For this simple example, we want to avoid throwing
an exception (the default policy) and just return infinity.
We want to treat the distribution as if it was continuous,
so we choose a discrete_quantile policy of real,
rather than the default policy integer_round_outwards.
*/
#define BOOST_MATH_OVERFLOW_ERROR_POLICY ignore_error
#define BOOST_MATH_DISCRETE_QUANTILE_POLICY real
/*`
[caution It is vital to #include distributions etc *after* the above #defines]
After that we need some includes to provide easy access to the negative binomial distribution,
and we need some std library iostream, of course.
*/
#include <boost/math/distributions/geometric.hpp>
  // for geometric_distribution
  using ::boost::math::geometric_distribution; //
  using ::boost::math::geometric; // typedef provides default type is double.
  using  ::boost::math::pdf; // Probability mass function.
  using  ::boost::math::cdf; // Cumulative density function.
  using  ::boost::math::quantile;

#include <boost/math/distributions/negative_binomial.hpp>
  // for negative_binomial_distribution
  using boost::math::negative_binomial; // typedef provides default type is double.

#include <boost/math/distributions/normal.hpp>
  // for negative_binomial_distribution
  using boost::math::normal; // typedef provides default type is double.

#include <iostream>
  using std::cout; using std::endl;
  using std::noshowpoint; using std::fixed; using std::right; using std::left;
#include <iomanip>
  using std::setprecision; using std::setw;

#include <limits>
  using std::numeric_limits;
//] [geometric_eg1_1]

int main()
{
  cout <<"Geometric distribution example" << endl;
  cout << endl;

  cout.precision(4); // But only show a few for this example.
  try
  {
//[geometric_eg1_2
/*`
It is always sensible to use try and catch blocks because defaults policies are to
throw an exception if anything goes wrong.

Simple try'n'catch blocks (see below) will ensure that you get a
helpful error message instead of an abrupt (and silent) program abort.

[h6 Throwing a dice]
The Geometric distribution describes the probability (/p/) of a number of failures
to get the first success in /k/ Bernoulli trials.
(A [@http://en.wikipedia.org/wiki/Bernoulli_distribution Bernoulli trial]
is one with only two possible outcomes, success of failure,
and /p/ is the probability of success).

Suppose an 'fair' 6-face dice is thrown repeatedly:
*/
    double success_fraction = 1./6; // success_fraction (p) = 0.1666
    // (so failure_fraction is 1 - success_fraction = 5./6 = 1- 0.1666 = 0.8333)

/*`If the dice is thrown repeatedly until the *first* time a /three/ appears.
The probablility distribution of the number of times it is thrown *not* getting a /three/
 (/not-a-threes/ number of failures to get a /three/)
is a geometric distribution with the success_fraction = 1/6 = 0.1666[recur].

We therefore start by constructing a geometric distribution
with the one parameter success_fraction, the probability of success.
*/
    geometric g6(success_fraction); // type double by default.
/*`
To confirm, we can echo the success_fraction parameter of the distribution.
*/
    cout << "success fraction of a six-sided dice is " << g6.success_fraction() << endl;
/*`So the probability of getting a three at the first throw (zero failures) is
*/
    cout << pdf(g6, 0) << endl; // 0.1667
    cout << cdf(g6, 0) << endl; // 0.1667
/*`Note that the cdf and pdf are identical because the is only one throw.
If we want the probability of getting the first /three/ on the 2nd throw:
*/
    cout << pdf(g6, 1) << endl; // 0.1389

/*`If we want the probability of getting the first /three/ on the 1st or 2nd throw
(allowing one failure):
*/
    cout << "pdf(g6, 0) + pdf(g6, 1) = " << pdf(g6, 0) + pdf(g6, 1) << endl;
/*`Or more conveniently, and more generally,
we can use the Cumulative Distribution Function CDF.*/

    cout << "cdf(g6, 1) = " << cdf(g6, 1) << endl; // 0.3056

/*`If we allow many more (12) throws, the probability of getting our /three/ gets very high:*/
    cout << "cdf(g6, 12) = " << cdf(g6, 12) << endl; // 0.9065 or 90% probability.
/*`If we want to be much more confident, say 99%,
we can estimate the number of throws to be this sure
using the inverse or quantile.
*/
    cout << "quantile(g6, 0.99) = " << quantile(g6, 0.99) << endl; // 24.26
/*`Note that the value returned is not an integer:
if you want an integer result you should use either floor, round or ceil functions,
or use the policies mechanism.
See [link math_toolkit.policy.pol_tutorial.understand_dis_quant
Understanding Quantiles of Discrete Distributions]

The geometric distribution is related to the negative binomial
__spaces `negative_binomial_distribution(RealType r, RealType p);` with parameter /r/ = 1.
So we could get the same result using the negative binomial,
but using the geometric the results will be faster, and may be more accurate.
*/
    negative_binomial nb(1, success_fraction);
    cout << pdf(nb, 1) << endl; // 0.1389
    cout << cdf(nb, 1) << endl; // 0.3056
/*`We could also the complement to express the required probability
as 1 - 0.99 = 0.01 (and get the same result):
*/
    cout << "quantile(complement(g6, 1 - p))  " << quantile(complement(g6, 0.01)) << endl; // 24.26
/*`
Note too that Boost.Math geometric distribution is implemented as a continuous function.
Unlike other implementations (for example R) it *uses* the number of failures as a *real* parameter,
not as an integer. If you want this integer behaviour, you may need to enforce this by
rounding the parameter you pass, probably rounding down, to the nearest integer.
For example, R returns the success fraction probability for all values of failures
from 0 to 0.999999 thus:
[pre
__spaces R> formatC(pgeom(0.0001,0.5, FALSE), digits=17) "               0.5"
] [/pre]
So in Boost.Math the equivalent is
*/
    geometric g05(0.5);  // Probability of success = 0.5 or 50%
    // Output all potentially significant digits for the type, here double.

#ifdef BOOST_NO_CXX11_NUMERIC_LIMITS
  int max_digits10 = 2 + (boost::math::policies::digits<double, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
  cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined" << endl;
#else
  int max_digits10 = std::numeric_limits<double>::max_digits10;
#endif
  cout << "Show all potentially significant decimal digits std::numeric_limits<double>::max_digits10 = "
    << max_digits10 << endl;
  cout.precision(max_digits10); //

    cout << cdf(g05, 0.0001) << endl; // returns 0.5000346561579232, not exact 0.5.
/*`To get the R discrete behaviour, you simply need to round with,
for example, the `floor` function.
*/
    cout << cdf(g05, floor(0.0001)) << endl; // returns exactly 0.5
/*`
[pre
`> formatC(pgeom(0.9999999,0.5, FALSE), digits=17) [1] "              0.25"`
`> formatC(pgeom(1.999999,0.5, FALSE), digits=17)[1] "              0.25" k = 1`
`> formatC(pgeom(1.9999999,0.5, FALSE), digits=17)[1] "0.12500000000000003" k = 2`
] [/pre]
shows that R makes an arbitrary round-up decision at about 1e7 from the next integer above.
This may be convenient in practice, and could be replicated in C++ if desired.

[h6 Surveying customers to find one with a faulty product]
A company knows from warranty claims that 2% of their products will be faulty,
so the 'success_fraction' of finding a fault is 0.02.
It wants to interview a purchaser of faulty products to assess their 'user experience'.

To estimate how many customers they will probably need to contact
in order to find one who has suffered from the fault,
we first construct a geometric distribution with probability 0.02,
and then chose a confidence, say 80%, 95%, or 99% to finding a customer with a fault.
Finally, we probably want to round up the result to the integer above using the `ceil` function.
(We could also use a policy, but that is hardly worthwhile for this simple application.)

(This also assumes that each customer only buys one product:
if customers bought more than one item,
the probability of finding a customer with a fault obviously improves.)
*/
    cout.precision(5);
    geometric g(0.02); // On average, 2 in 100 products are faulty.
    double c = 0.95; // 95% confidence.
    cout << " quantile(g, " << c << ") = " << quantile(g, c) << endl;

    cout << "To be " << c * 100
      << "% confident of finding we customer with a fault, need to survey "
      <<  ceil(quantile(g, c)) << " customers." << endl; // 148
    c = 0.99; // Very confident.
    cout << "To be " << c * 100
      << "% confident of finding we customer with a fault, need to survey "
      <<  ceil(quantile(g, c)) << " customers." << endl; // 227
    c = 0.80; // Only reasonably confident.
    cout << "To be " << c * 100
      << "% confident of finding we customer with a fault, need to survey "
      <<  ceil(quantile(g, c)) << " customers." << endl; // 79

/*`[h6 Basket Ball Shooters]
According to Wikipedia, average pro basket ball players get
[@http://en.wikipedia.org/wiki/Free_throw free throws]
in the baskets 70 to 80 % of the time,
but some get as high as 95%, and others as low as 50%.
Suppose we want to compare the probabilities
of failing to get a score only on the first or on the fifth shot?
To start we will consider the average shooter, say 75%.
So we construct a geometric distribution
with success_fraction parameter 75/100 = 0.75.
*/
    cout.precision(2);
    geometric gav(0.75); // Shooter averages 7.5 out of 10 in the basket.
/*`What is probability of getting 1st try in the basket, that is with no failures? */
    cout << "Probability of score on 1st try = " << pdf(gav, 0) << endl; // 0.75
/*`This is, of course, the success_fraction probability 75%.
What is the probability that the shooter only scores on the fifth shot?
So there are 5-1 = 4 failures before the first success.*/
    cout << "Probability of score on 5th try = " << pdf(gav, 4) << endl; // 0.0029
/*`Now compare this with the poor and the best players success fraction.
We need to constructing new distributions with the different success fractions,
and then get the corresponding probability density functions values:
*/
    geometric gbest(0.95);
    cout << "Probability of score on 5th try = " << pdf(gbest, 4) << endl; // 5.9e-6
    geometric gmediocre(0.50);
    cout << "Probability of score on 5th try = " << pdf(gmediocre, 4) << endl; // 0.031
/*`So we can see the very much smaller chance (0.000006) of 4 failures by the best shooters,
compared to the 0.03 of the mediocre.*/

/*`[h6 Estimating failures]
Of course one man's failure is an other man's success.
So a fault can be defined as a 'success'.

If a fault occurs once after 100 flights, then one might naively say
that the risk of fault is obviously 1 in 100 = 1/100, a probability of 0.01.

This is the best estimate we can make, but while it is the truth,
it is not the whole truth,
for it hides the big uncertainty when estimating from a single event.
"One swallow doesn't make a summer."
To show the magnitude of the uncertainty, the geometric
(or the negative binomial) distribution can be used.

If we chose the popular 95% confidence in the limits, corresponding to an alpha of 0.05,
because we are calculating a two-sided interval, we must divide alpha by two.
*/
    double alpha = 0.05;
    double k = 100; // So frequency of occurence is 1/100.
    cout << "Probability is failure is " << 1/k << endl;
    double t = geometric::find_lower_bound_on_p(k, alpha/2);
    cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
      << t << endl; // 0.00025
    t = geometric::find_upper_bound_on_p(k, alpha/2);
    cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
      << t << endl; // 0.037
/*`So while we estimate the probability is 0.01, it might lie between 0.0003 and 0.04.
Even if we relax our confidence to alpha = 90%, the bounds only contract to 0.0005 and 0.03.
And if we require a high confidence, they widen to 0.00005 to 0.05.
*/
    alpha = 0.1; // 90% confidence.
    t = geometric::find_lower_bound_on_p(k, alpha/2);
    cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
      << t << endl; // 0.0005
    t = geometric::find_upper_bound_on_p(k, alpha/2);
    cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
      << t << endl; // 0.03

    alpha = 0.01; // 99% confidence.
    t = geometric::find_lower_bound_on_p(k, alpha/2);
    cout << "geometric::find_lower_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
      << t << endl; // 5e-005
    t = geometric::find_upper_bound_on_p(k, alpha/2);
    cout << "geometric::find_upper_bound_on_p(" << int(k) << ", " << alpha/2 << ") = "
        << t << endl; // 0.052
/*`In real life, there will usually be more than one event (fault or success),
when the negative binomial, which has the neccessary extra parameter, will be needed.
*/

/*`As noted above, using a catch block is always a good idea,
even if you hope not to use it!
*/
  }
  catch(const std::exception& e)
  { // Since we have set an overflow policy of ignore_error,
    // an overflow exception should never be thrown.
     std::cout << "\nMessage from thrown exception was:\n " << e.what() << std::endl;
/*`
For example, without a ignore domain error policy,
if we asked for ``pdf(g, -1)`` for example,
we would get an unhelpful abort, but with a catch:
[pre
Message from thrown exception was:
 Error in function boost::math::pdf(const exponential_distribution<double>&, double):
 Number of failures argument is -1, but must be >= 0 !
] [/pre]
*/
//] [/ geometric_eg1_2]
  }
  return 0;
}  // int main()

/*
Output is:

  Geometric distribution example

  success fraction of a six-sided dice is 0.1667
  0.1667
  0.1667
  0.1389
  pdf(g6, 0) + pdf(g6, 1) = 0.3056
  cdf(g6, 1) = 0.3056
  cdf(g6, 12) = 0.9065
  quantile(g6, 0.99) = 24.26
  0.1389
  0.3056
  quantile(complement(g6, 1 - p))  24.26
  0.5000346561579232
  0.5
   quantile(g, 0.95) = 147.28
  To be 95% confident of finding we customer with a fault, need to survey 148 customers.
  To be 99% confident of finding we customer with a fault, need to survey 227 customers.
  To be 80% confident of finding we customer with a fault, need to survey 79 customers.
  Probability of score on 1st try = 0.75
  Probability of score on 5th try = 0.0029
  Probability of score on 5th try = 5.9e-006
  Probability of score on 5th try = 0.031
  Probability is failure is 0.01
  geometric::find_lower_bound_on_p(100, 0.025) = 0.00025
  geometric::find_upper_bound_on_p(100, 0.025) = 0.037
  geometric::find_lower_bound_on_p(100, 0.05) = 0.00051
  geometric::find_upper_bound_on_p(100, 0.05) = 0.03
  geometric::find_lower_bound_on_p(100, 0.005) = 5e-005
  geometric::find_upper_bound_on_p(100, 0.005) = 0.052

*/


/*
    This file is part of control-lib.

    Copyright (c) 2020, 2021, 2022 Bernardo Fichera <bernardo.fichera@gmail.com>

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
*/

#ifndef CONTROLLIB_SPATIAL_SE3_HPP
#define CONTROLLIB_SPATIAL_SE3_HPP

#include <Eigen/Geometry>

namespace control_lib {
    namespace spatial {
        struct SE3 {
            /* Init via translation and orientation */
            SE3(const Eigen::Matrix3d& rot, const Eigen::Vector3d& trans) : _rot(rot), _trans(trans) {}

            /* Init via vector representation */
            SE3(const Eigen::Matrix<double, 6, 1>& x) : _trans(x.head(3)), _rot(Eigen::AngleAxisd(x.tail(3).norm(), x.tail(3).normalized())) {}

            /* Default constructor */
            SE3() = default;

            /* Space elements difference */
            Eigen::Matrix<double, 6, 1> operator-(SE3 const& obj) const { return obj.actionInverse(*this).log(); }

            /* Space dimension */
            constexpr static size_t dimension() { return 6; }

            /* Translation & rotation */
            Eigen::Vector3d _trans;
            Eigen::Matrix3d _rot;

            /* Tangent and contagent plane elements (optionals) */
            Eigen::Matrix<double, 6, 1> _vel, _acc, _eff;

        protected:
            SE3 action(const SE3& pose) const { return SE3(_rot * pose._rot, _trans + _rot * pose._trans); }

            SE3 actionInverse(const SE3& pose) const { return SE3(_rot.transpose() * pose._rot, _rot.transpose() * (pose._trans - _trans)); }

            Eigen::Matrix<double, 6, 1> log(const SE3& pose) const
            {
                Eigen::AngleAxisd aa(pose._rot);

                Eigen::Vector3d omega = aa.angle() * aa.axis();

                Eigen::Matrix3d omega_skew;
                omega_skew << 0, -omega(2), omega(1),
                    omega(2), 0, -omega(0),
                    -omega(1), omega(0), 0;

                double theta = omega.norm(), A = std::sin(theta) / theta, B = (1 - std::cos(theta)) / std::pow(theta, 2);

                return (Eigen::Matrix<double, 6, 1>() << (Eigen::Matrix3d::Identity() - 0.5 * omega_skew + (1 - 0.5 * A / B) / std::pow(theta, 2) * omega_skew * omega_skew) * pose._trans, omega).finished();
            }

            Eigen::Matrix<double, 6, 1> log() { return log(*this); }
        };
    } // namespace spatial

} // namespace control_lib

#endif // CONTROLLIB_SPATIAL_SE3_HPP


/**
 * $Id$
 *
 * Copyright (C)
 * 2015 - $Date$
 *     Martin Wolf <ndhist@martin-wolf.org>
 *
 * This file is distributed under the BSD 2-Clause Open Source License
 * (See LICENSE file).
 *
 */
#ifndef NDHIST_STATS_KURTOSIS_HPP_INCLUDED
#define NDHIST_STATS_KURTOSIS_HPP_INCLUDED 1

#include <boost/python.hpp>

#include <ndhist/ndhist.hpp>
#include <ndhist/stats/expectation.hpp>
#include <ndhist/stats/var.hpp>

namespace ndhist {
namespace stats {

namespace detail {

template <typename AxisValueType, typename WeightValueType>
double
calc_axis_kurtosis_impl(
    ndhist const & h
  , intptr_t const axis
)
{
    // Do the projection here, so it won't be done twice.
    ndhist const proj = (h.get_nd() == 1 ? h : h.project(bp::object(axis)));

    double const expact1 = calc_axis_expectation_impl<AxisValueType, WeightValueType>(proj, 1, axis);
    double const expact2 = calc_axis_expectation_impl<AxisValueType, WeightValueType>(proj, 2, axis);
    double const expact3 = calc_axis_expectation_impl<AxisValueType, WeightValueType>(proj, 3, axis);
    double const expact4 = calc_axis_expectation_impl<AxisValueType, WeightValueType>(proj, 4, axis);
    double const var = calc_axis_var_impl<AxisValueType, WeightValueType>(proj, axis);

    // Kurtosis[x] = (E[x^4] - 4 E[x] E[x^3] + 6 E[x]^2 E[x^2] - 3 E[x]^4) / V[x]^2
    return (expact4 - 4*expact1*expact3 + 6*expact1*expact1*expact2 - 3*expact1*expact1*expact1*expact1) / (var*var);
}

}// namespace detail

namespace py {

/**
 * @brief Calculates the kurtosis along the given axis of the given
 *     ndhist object. As in statistics, the kurtosis is defined as
 *     :math:`Kurtosis[x] = (E[x^4] - 4 E[x] E[x^3] + 6 E[x]^2 E[x^2] - 3 E[x]^4) / V[x]^2`.
 *     This function generates a projection along the given axis and then
 *     calculates the kurtosis.
 *     If None is given as axis, the kurtosis for all individual axes of the
 *     ndhist object will be calculated and returned as a tuple. But if the
 *     dimensionality of the ndhist object is 1, a scalar value is returned.
 *
 * @note This function is only defined for ndhist objects with POD axis values
 *     AND POD weight values.
 */
boost::python::object
kurtosis(
    ndhist const & h
  , boost::python::object const & axis = boost::python::object()
);

}// namespace py

}// namespace stats
}// namespace ndhist

#endif // NDHIST_STATS_KURTOSIS_HPP_INCLUDED


#include <iostream>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

typedef boost::numeric::ublas::matrix<float> Matrix44;
//typedef boost::numeric::ublas

int main()
{
	Matrix44 matrix = boost::numeric::ublas::identity_matrix<float> (4);

	std::cout << matrix << std::endl;

	return 0;
}


// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
/*

 This simple example shows how to call dlib's optimal linear assignment problem solver.
 It is an implementation of the famous Hungarian algorithm and is quite fast, operating in
 O(N^3) time.

*/

#include <dlib/optimization/max_cost_assignment.h>
#include <iostream>

using namespace std;
using namespace dlib;

int main ()
{
    // Let's imagine you need to assign N people to N jobs.  Additionally, each person will make
    // your company a certain amount of money at each job, but each person has different skills
    // so they are better at some jobs and worse at others.  You would like to find the best way
    // to assign people to these jobs.  In particular, you would like to maximize the amount of
    // money the group makes as a whole.  This is an example of an assignment problem and is
    // what is solved by the max_cost_assignment() routine.
    //
    // So in this example, let's imagine we have 3 people and 3 jobs.  We represent the amount of
    // money each person will produce at each job with a cost matrix.  Each row corresponds to a
    // person and each column corresponds to a job.  So for example, below we are saying that
    // person 0 will make $1 at job 0, $2 at job 1, and $6 at job 2.
    matrix<int> cost(3,3);
    cost = 1, 2, 6,
           5, 3, 6,
           4, 5, 0;

    // To find out the best assignment of people to jobs we just need to call this function.
    std::vector<long> assignment = max_cost_assignment(cost);

    // This prints optimal assignments:  [2, 0, 1] which indicates that we should assign
    // the person from the first row of the cost matrix to job 2, the middle row person to
    // job 0, and the bottom row person to job 1.
    for (unsigned int i = 0; i < assignment.size(); i++)
        cout << assignment[i] << std::endl;

    // This prints optimal cost:  16.0
    // which is correct since our optimal assignment is 6+5+5.
    cout << "optimal cost: " << assignment_cost(cost, assignment) << endl;
}


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

//Cross Product Equivalent
using Eigen::Matrix3f;
using Eigen::Vector3f;
Matrix3f crossProductEquivalent(Vector3f v)
{
  std::cout << v <<std::endl;
  std::cout << v(2) <<std::endl;
  Matrix3f c;
  c << 0, -v(2), v(1),
       v(2), 0, -v(0),
       -v(1), v(0), 0;
  std::cout << c << std::endl;
  return c;
}

int main()
{
  Vector3f v;
  v << 1,
       2,
       3;
  crossProductEquivalent(v);
}


#include <iostream>
#include <Eigen/Dense>
#include "../simple_lib/include/simple_activation.h"
#include <map>
#include <string>

using namespace Eigen;

// prototype declaration
std::map<std::string, MatrixXd> init_network(void);
MatrixXd forward(std::map<std::string, MatrixXd> network, MatrixXd x);

// main function
int main(){
    using std::cout;
    using std::endl;
    using std::map;
    using std::string;

    MatrixXd X  = MatrixXd::Zero(1, 2);
    MatrixXd W1 = MatrixXd::Zero(2, 3);
    MatrixXd B1 = MatrixXd::Zero(1, 3);
    MatrixXd A1 = MatrixXd::Zero(1, 3);
    MatrixXd Z1 = MatrixXd::Zero(1, 3);
    MatrixXd W2 = MatrixXd::Zero(3, 2);
    MatrixXd B2 = MatrixXd::Zero(1, 2);
    MatrixXd A2 = MatrixXd::Zero(1, 2);
    MatrixXd Z2 = MatrixXd::Zero(1, 2);
    MatrixXd W3 = MatrixXd::Zero(2, 2);
    MatrixXd B3 = MatrixXd::Zero(1, 2);
    MatrixXd A3 = MatrixXd::Zero(1, 2);
    MatrixXd Y  = MatrixXd::Zero(1, 2);

    X << 1.0, 0.5;
    W1 << 0.1, 0.3, 0.5,  0.2, 0.4, 0.6;
    B1 << 0.1, 0.2, 0.3;

    W2 << 0.1, 0.4,  0.2, 0.5,  0.3, 0.6;
    B2 << 0.1, 0.2;

    W3 << 0.1, 0.3,  0.2, 0.4;
    B3 << 0.1, 0.2;

    A1 = X * W1 + B1;

    cout << "A1 = " << A1 << endl;

    Z1 = A1.unaryExpr([](double p){return MyDL::sigmoid<double>(p);});

    cout << "Z1 = " << Z1 << endl;

    A2 = Z1 * W2 + B2;
    Z2 = A2.unaryExpr([] (double p){return MyDL::sigmoid<double>(p);});

    cout << "A2 = " << A2 << endl;
    cout << "Z2 = " << Z2 << endl;

    A3 = Z2 * W3 + B3;
    Y = A3.unaryExpr([] (double p){return MyDL::identity_function<double>(p);});

    cout << "A3 = " << A3 << endl;
    cout << "Y = " << Y << endl;

    // call network function -> last activation is Softmax function
    map <string, MatrixXd> network;
    network = init_network();
    Y = forward(network, X);

    cout << "Function ver: Y = " << Y << endl;

    return 0;
}

// Implementation
std::map<std::string, MatrixXd> init_network(void)
{

    using std::map;
    using std::string;

    map<string, MatrixXd> network;

    MatrixXd W1 = MatrixXd::Zero(2, 3);
    MatrixXd b1 = MatrixXd::Zero(1, 3);
    MatrixXd W2 = MatrixXd::Zero(3, 2);
    MatrixXd b2 = MatrixXd::Zero(1, 2);
    MatrixXd W3 = MatrixXd::Zero(2, 2);
    MatrixXd b3 = MatrixXd::Zero(1, 2);

    W1 << 0.1, 0.3, 0.5, 0.2, 0.4, 0.6;
    b1 << 0.1, 0.2, 0.3;
    W2 << 0.1, 0.4, 0.2, 0.5, 0.3, 0.6;
    b2 << 0.1, 0.2;
    W3 << 0.1, 0.3, 0.2, 0.4;
    b3 << 0.1, 0.2;

    network["W1"] = W1;
    network["b1"] = b1;
    network["W2"] = W2;
    network["b2"] = b2;
    network["W3"] = W3;
    network["b3"] = b3;

    return network;
}

MatrixXd forward(std::map<std::string, MatrixXd> network, MatrixXd x)
{
    using std::map;
    using std::string;

    MatrixXd W1 = MatrixXd::Zero(2, 3);
    MatrixXd b1 = MatrixXd::Zero(1, 3);
    MatrixXd W2 = MatrixXd::Zero(3, 2);
    MatrixXd b2 = MatrixXd::Zero(1, 2);
    MatrixXd W3 = MatrixXd::Zero(2, 2);
    MatrixXd b3 = MatrixXd::Zero(1, 2);

    MatrixXd a1 = MatrixXd::Zero(1, 3);
    MatrixXd z1 = MatrixXd::Zero(1, 3);
    MatrixXd a2 = MatrixXd::Zero(1, 2);
    MatrixXd z2 = MatrixXd::Zero(1, 2);
    MatrixXd a3 = MatrixXd::Zero(1, 2);
    MatrixXd y = MatrixXd::Zero(1, 2);

    W1 = network["W1"];
    b1 = network["b1"];
    W2 = network["W2"];
    b2 = network["b2"];
    W3 = network["W3"];
    b3 = network["b3"];

    a1 = x * W1 + b1;
    z1 = a1.unaryExpr([] (double p){return MyDL::sigmoid<double>(p);});
    a2 = z1 * W2 + b2;
    z2 = a2.unaryExpr([] (double p){return MyDL::sigmoid<double>(p);});
    a3 = z2 * W3 + b3;
    y  = MyDL::softmax(a3);

    return y;
}