#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/complex.h>
#include <pybind11/numpy.h>
#include <boost/lexical_cast.hpp>

#include <assert.h>
#include <vector>

#include <CGAL/Kernel/global_functions.h>

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>

typedef CGAL::Exact_predicates_inexact_constructions_kernel            Kernel;
typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
typedef CGAL::Triangulation_data_structure_2<Vb>                       Tds;
typedef CGAL::Delaunay_triangulation_2<Kernel, Tds>                    Delaunay;
typedef Kernel::Point_2 Point;

typedef CGAL::Triangulation_vertex_base_with_info_3<unsigned int, Kernel> Vb3;
typedef CGAL::Triangulation_data_structure_3<Vb3>                       Tds3;
typedef CGAL::Delaunay_triangulation_3<Kernel, Tds3>                    Delaunay3;
typedef Kernel::Point_3 Point3;

std::vector<double> c_circumballs2(std::vector<double> &vertices)
{
    int num_faces = vertices.size()/6;
    std::vector<double> circumcenters;
    for(std::size_t i=0; i < num_faces; ++i)
    {
        Point tmp_cc =
                CGAL::circumcenter(
                Point(vertices[i*6],vertices[i*6+1]),
                Point(vertices[i*6+2],vertices[i*6+3]),
                Point(vertices[i*6+4],vertices[i*6+5])
                );
        circumcenters.push_back(tmp_cc.x());
        circumcenters.push_back(tmp_cc.y());
        circumcenters.push_back(
                CGAL::squared_radius(
                    Point(vertices[i*6],vertices[i*6+1]),
                    Point(vertices[i*6+2],vertices[i*6+3]),
                    Point(vertices[i*6+4],vertices[i*6+5])
                    )
                );
    }
    return circumcenters;
}

std::vector<double> c_circumballs3(std::vector<double> &vertices)
{
    int num_cells = vertices.size()/12;
    std::vector<double> circumcenters;
    for(std::size_t i=0; i < num_cells; ++i)
    {
        Point3 tmp_cc =
                CGAL::circumcenter(
                Point3(vertices[i*12],vertices[i*12+1],vertices[i*12+2]),
                Point3(vertices[i*12+3],vertices[i*12+4],vertices[i*12+5]),
                Point3(vertices[i*12+6],vertices[i*12+7],vertices[i*12+8]),
                Point3(vertices[i*12+9], vertices[i*12+10],vertices[i*12+11])
                );
        circumcenters.push_back(tmp_cc.x());
        circumcenters.push_back(tmp_cc.y());
        circumcenters.push_back(tmp_cc.z());
        circumcenters.push_back(
                CGAL::squared_radius(
                Point3(vertices[i*12],vertices[i*12+1],vertices[i*12+2]),
                Point3(vertices[i*12+3],vertices[i*12+4],vertices[i*12+5]),
                Point3(vertices[i*12+6],vertices[i*12+7],vertices[i*12+8]),
                Point3(vertices[i*12+9], vertices[i*12+10],vertices[i*12+11]))
                );
    }
    return circumcenters;
}

std::vector<int> c_delaunay2(std::vector<double> &x, std::vector<double> &y)
{
  int num_points = x.size();
  assert(y.size()!=num_points);
  std::vector< std::pair<Point,unsigned> > points;
  // add index information to form face table later
  for(std::size_t i = 0; i < num_points; ++i)
  {
     points.push_back( std::make_pair( Point(x[i],y[i]), i ) );
  }

  Delaunay triangulation;
  triangulation.insert(points.begin(),points.end());

  // save the face table
  int num_faces = triangulation.number_of_faces();
  std::vector<int> faces;
  faces.resize(num_faces*3);

  int i=0;
  for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
    fit != triangulation.finite_faces_end(); ++fit) {

    Delaunay::Face_handle face = fit;
    faces[i*3]=face->vertex(0)->info();
    faces[i*3+1]=face->vertex(1)->info();
    faces[i*3+2]=face->vertex(2)->info();
    i+=1;
  }
  return faces;
}

std::vector<int> c_delaunay3(std::vector<double> &x, std::vector<double> &y, std::vector<double> &z)
{
  int num_points = x.size();
  assert(y.size()!=num_points);
  assert(z.size()!=num_points);
  std::vector< std::pair<Point3,unsigned> > points;
  // add index information to form face table later
  for(std::size_t i = 0; i < num_points; ++i)
  {
     points.push_back( std::make_pair( Point3(x[i],y[i],z[i]), i ) );
  }
  Delaunay3 triangulation;
  triangulation.insert(points.begin(),points.end());
  // save the indices of all cells
  int num_cells = triangulation.number_of_finite_cells();
  std::vector<int> cells;
  cells.resize(num_cells*4);

  int i=0;
  for(Delaunay3::Finite_cells_iterator cit = triangulation.finite_cells_begin();
    cit != triangulation.finite_cells_end(); ++cit) {

    Delaunay3::Cell_handle cell = cit;
    cells[i*4]=cell->vertex(0)->info();
    cells[i*4+1]=cell->vertex(1)->info();
    cells[i*4+2]=cell->vertex(2)->info();
    cells[i*4+3]=cell->vertex(3)->info();
    i+=1;
  }
  return cells;
}

// ----------------
// Python interface
// ----------------
// (from https://github.com/tdegeus/pybind11_examples/blob/master/04_numpy-2D_cpp-vector/example.cpp)

namespace py = pybind11;
py::array circumballs2(py::array_t<double, py::array::c_style | py::array::forcecast> vertices)
{
    // each triangle has 3 vertices with 2 coordinates each
    int sz = vertices.shape()[0];
    std::vector<double> cppvertices(sz);
    std::memcpy(cppvertices.data(),vertices.data(),sz*sizeof(double));
    std::vector<double> circumcenters = c_circumballs2(cppvertices);
    ssize_t              soreal      = sizeof(double);
    ssize_t              num_points = circumcenters.size()/3;
    ssize_t              ndim      = 2;
    std::vector<ssize_t> shape     = {num_points, 3};
    std::vector<ssize_t> strides   = {soreal*3, soreal};
    // return 2-D NumPy array
    return py::array(py::buffer_info(
        circumcenters.data(),                    /* data as contiguous array  */
        sizeof(double),                          /* size of one scalar        */
        py::format_descriptor<double>::format(), /* data type                 */
        2,                                       /* number of dimensions      */
        shape,                                   /* shape of the matrix       */
        strides                                  /* strides for each axis     */
  ));
}

py::array circumballs3(py::array_t<double, py::array::c_style | py::array::forcecast> vertices)
{
    // each triangle has 4 vertices with 3 coordinates each
    int sz = vertices.size();
    std::vector<double> cppvertices(sz);
    std::memcpy(cppvertices.data(),vertices.data(),sz*sizeof(double));
    std::vector<double> circumcenters = c_circumballs3(cppvertices);
    ssize_t              soreal      = sizeof(double);
    ssize_t              num_points = circumcenters.size()/4;
    ssize_t              ndim      = 2;
    std::vector<ssize_t> shape     = {num_points, 4};
    std::vector<ssize_t> strides   = {soreal*4, soreal};
    // return 2-D NumPy array
    return py::array(py::buffer_info(
        circumcenters.data(),                    /* data as contiguous array  */
        sizeof(double),                          /* size of one scalar        */
        py::format_descriptor<double>::format(), /* data type                 */
        2,                                       /* number of dimensions      */
        shape,                                   /* shape of the matrix       */
        strides                                  /* strides for each axis     */
  ));
}

py::array delaunay2(py::array_t<double, py::array::c_style | py::array::forcecast> x,
                    py::array_t<double, py::array::c_style | py::array::forcecast> y)
{

  // check input dimensions
  if ( x.ndim() != 1 )
    throw std::runtime_error("Input should be 2 1D NumPy arrays");
  if ( y.ndim() != 1 )
    throw std::runtime_error("Input should be 2 1D NumPy arrays");

  int num_points = x.shape()[0];

  // allocate std::vector (to pass to the C++ function)
  std::vector<double> cppx(num_points);
  std::vector<double> cppy(num_points);

  // copy py::array -> std::vector
  std::memcpy(cppx.data(),x.data(),num_points*sizeof(double));
  std::memcpy(cppy.data(),y.data(),num_points*sizeof(double));
  std::vector<int> faces = c_delaunay2(cppx, cppy);

  ssize_t              soint      = sizeof(int);
  ssize_t              num_faces = faces.size()/3;
  ssize_t              ndim      = 2;
  std::vector<ssize_t> shape     = {num_faces, 3};
  std::vector<ssize_t> strides   = {soint*3, soint};

  // return 2-D NumPy array
  return py::array(py::buffer_info(
    faces.data(),                           /* data as contiguous array  */
    sizeof(int),                          /* size of one scalar        */
    py::format_descriptor<int>::format(), /* data type                 */
    2,                                    /* number of dimensions      */
    shape,                                   /* shape of the matrix       */
    strides                                  /* strides for each axis     */
  ));
}

py::array delaunay3(py::array_t<double, py::array::c_style | py::array::forcecast> x,
                    py::array_t<double, py::array::c_style | py::array::forcecast> y,
                    py::array_t<double, py::array::c_style | py::array::forcecast> z)
{

  // check input dimensions
  if ( x.ndim() != 1 )
    throw std::runtime_error("Input should be three 1D NumPy arrays");
  if ( y.ndim() != 1 )
    throw std::runtime_error("Input should be three 1D NumPy arrays");
  if ( z.ndim() != 1 )
    throw std::runtime_error("Input should be three 1D NumPy arrays");

  int num_points = x.shape()[0];

  // allocate std::vector (to pass to the C++ function)
  std::vector<double> cppx(num_points);
  std::vector<double> cppy(num_points);
  std::vector<double> cppz(num_points);

  // copy py::array -> std::vector
  std::memcpy(cppx.data(),x.data(),num_points*sizeof(double));
  std::memcpy(cppy.data(),y.data(),num_points*sizeof(double));
  std::memcpy(cppz.data(),z.data(),num_points*sizeof(double));
  std::vector<int> cells = c_delaunay3(cppx, cppy, cppz);

  ssize_t              num_cells = cells.size()/4;
  ssize_t              ndim      = 2;
  ssize_t              soint      = sizeof(int);
  std::vector<ssize_t> shape     = {num_cells, 4};
  std::vector<ssize_t> strides   = {soint*4, soint};

  // return 2-D NumPy array
  return py::array(py::buffer_info(
    cells.data(),                           /* data as contiguous array  */
    sizeof(int),                          /* size of one scalar        */
    py::format_descriptor<int>::format(), /* data type                 */
    2,                                    /* number of dimensions      */
    shape,                                   /* shape of the matrix       */
    strides                                  /* strides for each axis     */
  ));
}

PYBIND11_MODULE(c_cgal, m) {
    m.def("circumballs3", &circumballs3);
    m.def("circumballs2", &circumballs2);
    m.def("delaunay2", &delaunay2);
    m.def("delaunay3", &delaunay3);
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <array>
//#include <boost/multiprecision/cpp_int.hpp>
// using namespace boost::multiprecision;
const int mx = 1e6 + 5;
using ll = int64_t;

std::array<ll, mx> parent;
ll node, edge;
std::vector<std::pair<ll, std::pair<ll, ll>>> edges;
void initial() {
    for (int i = 0; i < node + edge; ++i) {
      parent[i] = i;
    }
}

int root(int i) {
    while (parent[i] != i) {
        parent[i] = parent[parent[i]];
        i = parent[i];
    }
    return i;
}

void join(int x, int y) {
    int root_x = root(x);  // Disjoint set union by rank
    int root_y = root(y);
    parent[root_x] = root_y;
}

ll kruskal() {
    ll mincost = 0;
    for (int i = 0; i < edge; ++i) {
        ll x = edges[i].second.first;
        ll y = edges[i].second.second;
        if (root(x) != root(y)) {
            mincost += edges[i].first;
            join(x, y);
        }
    }
    return mincost;
}

int main() {
    while (true) {
        int from = 0, to = 0, cost = 0, totalcost = 0;
        std::cin >> node >> edge;  // Enter the nodes and edges
        if (node == 0 && edge == 0) {
            break;  // Enter 0 0 to break out
        }
        initial();  // Initialise the parent array
        for (int i = 0; i < edge; ++i) {
            std::cin >> from >> to >> cost;
            edges.emplace_back(make_pair(cost, std::make_pair(from, to)));
            totalcost += cost;
        }
        sort(edges.begin(), edges.end());
        std::cout << kruskal() << std::endl;
        edges.clear();
    }
    return 0;
}


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

/*
 Copyright (C) 2002, 2003 Ferdinando Ametrano
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
 Copyright (C) 2010 Kakhkhor Abdijalilov

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it
 under the terms of the QuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 <quantlib-dev@lists.sf.net>. The license is also available online at
 <http://quantlib.org/license.shtml>.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

/*! \file normaldistribution.hpp
    \brief normal, cumulative and inverse cumulative distributions
*/

#ifndef quantlib_normal_distribution_hpp
#define quantlib_normal_distribution_hpp

#include <ql/math/errorfunction.hpp>
#include <ql/errors.hpp>
#include <ql/math/comparison.hpp>

#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif

#include <boost/math/distributions/normal.hpp>

#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4))
#pragma GCC diagnostic pop
#endif

namespace QuantLib {

    //! Normal distribution function
    /*! Given x, it returns its probability in a Gaussian normal distribution.
        It provides the first derivative too.

        \test the correctness of the returned value is tested by
              checking it against numerical calculations. Cross-checks
              are also performed against the
              CumulativeNormalDistribution and InverseCumulativeNormal
              classes.
    */
    class NormalDistribution : public std::unary_function<Real,Real> {
      public:
        NormalDistribution(Real average = 0.0,
                           Real sigma = 1.0);
        // function
        Real operator()(Real x) const;
        Real derivative(Real x) const;
      private:
        Real average_, sigma_, normalizationFactor_, denominator_,
            derNormalizationFactor_;
    };

    typedef NormalDistribution GaussianDistribution;

    //! Cumulative normal distribution function
    /*! Given x it provides an approximation to the
        integral of the gaussian normal distribution:
        formula here ...

        For this implementation see M. Abramowitz and I. Stegun,
        Handbook of Mathematical Functions,
        Dover Publications, New York (1972)
    */
    class CumulativeNormalDistribution
    : public std::unary_function<Real,Real> {
      public:
        CumulativeNormalDistribution(Real average = 0.0,
                                     Real sigma   = 1.0);
        // function
        Real operator()(Real x) const;
        Real derivative(Real x) const;
      private:
        Real average_, sigma_;
        NormalDistribution gaussian_;
        ErrorFunction errorFunction_;
    };

    //! Inverse cumulative normal distribution function
    /*! Given x between zero and one as
      the integral value of a gaussian normal distribution
      this class provides the value y such that
      formula here ...

      It use Acklam's approximation:
      by Peter J. Acklam, University of Oslo, Statistics Division.
      URL: http://home.online.no/~pjacklam/notes/invnorm/index.html

      This class can also be used to generate a gaussian normal
      distribution from a uniform distribution.
      This is especially useful when a gaussian normal distribution
      is generated from a low discrepancy uniform distribution:
      in this case the traditional Box-Muller approach and its
      variants would not preserve the sequence's low-discrepancy.

    */
    class InverseCumulativeNormal
        : public std::unary_function<Real,Real> {
      public:
        InverseCumulativeNormal(Real average = 0.0,
                                Real sigma   = 1.0);
        // function
        Real operator()(Real x) const {
            return average_ + sigma_*standard_value(x);
        }
        // value for average=0, sigma=1
        /* Compared to operator(), this method avoids 2 floating point
           operations (we use average=0 and sigma=1 most of the
           time). The speed difference is noticeable.
        */
        static Real standard_value(Real x) {
            Real z;
            if (x < x_low_() || x_high_() < x) {
                z = tail_value(x);
            } else {
                z = x - 0.5;
                Real r = z*z;
                z = (((((a1_()*r+a2_())*r+a3_())*r+a4_())*r+a5_())*r+a6_())*z /
                    (((((b1_()*r+b2_())*r+b3_())*r+b4_())*r+b5_())*r+1.0);
            }

            // The relative error of the approximation has absolute value less
            // than 1.15e-9.  One iteration of Halley's rational method (third
            // order) gives full machine precision.
            // #define REFINE_TO_FULL_MACHINE_PRECISION_USING_HALLEYS_METHOD
            #ifdef REFINE_TO_FULL_MACHINE_PRECISION_USING_HALLEYS_METHOD
            // error (f_(z) - x) divided by the cumulative's derivative
            const Real r = (f_(z) - x) * M_SQRT2 * M_SQRTPI * exp(0.5 * z*z);
            //  Halley's method
            z -= r/(1+0.5*z*r);
            #endif

            return z;
        }
      private:
        /* Handling tails moved into a separate method, which should
           make the inlining of operator() and standard_value method
           easier. tail_value is called rarely and doesn't need to be
           inlined.
        */
        static Real tail_value(Real x);
        #if defined(QL_PATCH_SOLARIS)
        CumulativeNormalDistribution f_;
        #else
        static const CumulativeNormalDistribution f_;
        #endif
        Real average_, sigma_;
        // Coefficients for the rational approximation.
        static Real a1_() { return -3.969683028665376e+01; }
        static Real a2_() { return 2.209460984245205e+02; }
        static Real a3_() { return -2.759285104469687e+02; }
        static Real a4_() { return 1.383577518672690e+02; }
        static Real a5_() { return -3.066479806614716e+01; }
        static Real a6_() { return 2.506628277459239e+00; }

        static Real b1_() { return -5.447609879822406e+01; }
        static Real b2_() { return 1.615858368580409e+02; }
        static Real b3_() { return -1.556989798598866e+02; }
        static Real b4_() { return 6.680131188771972e+01; }
        static Real b5_() { return -1.328068155288572e+01; }

        static Real c1_() { return -7.784894002430293e-03; }
        static Real c2_() { return -3.223964580411365e-01; }
        static Real c3_() { return -2.400758277161838e+00; }
        static Real c4_() { return -2.549732539343734e+00; }
        static Real c5_() { return 4.374664141464968e+00; }
        static Real c6_() { return 2.938163982698783e+00; }

        static Real d1_() { return 7.784695709041462e-03; }
        static Real d2_() { return 3.224671290700398e-01; }
        static Real d3_() { return 2.445134137142996e+00; }
        static Real d4_() { return 3.754408661907416e+00; }

        // Limits of the approximation regions
        static Real x_low_() { return 0.02425; }
        static Real x_high_() { return 1.0 - x_low_(); }
    };

    // backward compatibility
    typedef InverseCumulativeNormal InvCumulativeNormalDistribution;

    //! Moro Inverse cumulative normal distribution class
    /*! Given x between zero and one as
        the integral value of a gaussian normal distribution
        this class provides the value y such that
        formula here ...

        It uses Beasly and Springer approximation, with an improved
        approximation for the tails. See Boris Moro,
        "The Full Monte", 1995, Risk Magazine.

        This class can also be used to generate a gaussian normal
        distribution from a uniform distribution.
        This is especially useful when a gaussian normal distribution
        is generated from a low discrepancy uniform distribution:
        in this case the traditional Box-Muller approach and its
        variants would not preserve the sequence's low-discrepancy.

        Peter J. Acklam's approximation is better and is available
        as QuantLib::InverseCumulativeNormal
    */
    class MoroInverseCumulativeNormal
    : public std::unary_function<Real,Real> {
      public:
        MoroInverseCumulativeNormal(Real average = 0.0,
                                    Real sigma   = 1.0);
        // function
        Real operator()(Real x) const;
      private:
        Real average_, sigma_;
        static Real a0_() { return 2.50662823884; }
        static Real a1_() { return -18.61500062529; }
        static Real a2_() { return 41.39119773534; }
        static Real a3_() { return -25.44106049637; }

        static Real b0_() { return -8.47351093090; }
        static Real b1_() { return 23.08336743743; }
        static Real b2_() { return -21.06224101826; }
        static Real b3_() { return 3.13082909833; }

        static Real c0_() { return 0.3374754822726147; }
        static Real c1_() { return 0.9761690190917186; }
        static Real c2_() { return 0.1607979714918209; }
        static Real c3_() { return 0.0276438810333863; }
        static Real c4_() { return 0.0038405729373609; }
        static Real c5_() { return 0.0003951896511919; }
        static Real c6_() { return 0.0000321767881768; }
        static Real c7_() { return 0.0000002888167364; }
        static Real c8_() { return 0.0000003960315187; }
    };

    //! Maddock's Inverse cumulative normal distribution class
    /*! Given x between zero and one as
        the integral value of a gaussian normal distribution
        this class provides the value y such that
        formula here ...

        From the boost documentation:
         These functions use a rational approximation devised by
         John Maddock to calculate an initial approximation to the
         result that is accurate to ~10^-19, then only if that has
         insufficient accuracy compared to the epsilon for type double,
         do we clean up the result using Halley iteration.
    */
    class MaddockInverseCumulativeNormal
    : public std::unary_function<Real,Real> {
      public:
        MaddockInverseCumulativeNormal(Real average = 0.0,
                                       Real sigma   = 1.0);
        Real operator()(Real x) const;

      private:
        const Real average_, sigma_;
    };

    //! Maddock's cumulative normal distribution class
    class MaddockCumulativeNormal : public std::unary_function<Real,Real> {
      public:
        MaddockCumulativeNormal(Real average = 0.0,
                                       Real sigma   = 1.0);
        Real operator()(Real x) const;

      private:
        const Real average_, sigma_;
    };

    // inline definitions

    inline NormalDistribution::NormalDistribution(Real average,
                                                  Real sigma)
    : average_(average), sigma_(sigma) {

        QL_REQUIRE(sigma_>0.0,
                   "sigma must be greater than 0.0 ("
                   << sigma_ << " not allowed)");

        normalizationFactor_ = M_SQRT_2*M_1_SQRTPI/sigma_;
        derNormalizationFactor_ = sigma_*sigma_;
        denominator_ = 2.0*derNormalizationFactor_;
    }

    inline Real NormalDistribution::operator()(Real x) const {
        Real deltax = x-average_;
        Real exponent = -(deltax*deltax)/denominator_;
        // debian alpha had some strange problem in the very-low range
        return exponent <= -690.0 ? 0.0 :  // exp(x) < 1.0e-300 anyway
            normalizationFactor_*std::exp(exponent);
    }

    inline Real NormalDistribution::derivative(Real x) const {
        return ((*this)(x) * (average_ - x)) / derNormalizationFactor_;
    }

    inline CumulativeNormalDistribution::CumulativeNormalDistribution(
                                                 Real average, Real sigma)
    : average_(average), sigma_(sigma) {

        QL_REQUIRE(sigma_>0.0,
                   "sigma must be greater than 0.0 ("
                   << sigma_ << " not allowed)");
    }

    inline Real CumulativeNormalDistribution::derivative(Real x) const {
        Real xn = (x - average_) / sigma_;
        return gaussian_(xn) / sigma_;
    }

    inline InverseCumulativeNormal::InverseCumulativeNormal(
                                                 Real average, Real sigma)
    : average_(average), sigma_(sigma) {

        QL_REQUIRE(sigma_>0.0,
                   "sigma must be greater than 0.0 ("
                   << sigma_ << " not allowed)");
    }

    inline MoroInverseCumulativeNormal::MoroInverseCumulativeNormal(
                                                 Real average, Real sigma)
    : average_(average), sigma_(sigma) {

        QL_REQUIRE(sigma_>0.0,
                   "sigma must be greater than 0.0 ("
                   << sigma_ << " not allowed)");
    }

    // implementation

    inline Real CumulativeNormalDistribution::operator()(Real z) const {
        //QL_REQUIRE(!(z >= average_ && 2.0*average_-z > average_),
        //           "not a real number. ");
        z = (z - average_) / sigma_;

        Real result = 0.5 * ( 1.0 + errorFunction_( z*M_SQRT_2 ) );
        if (result<=1e-8) { //todo: investigate the threshold level
            // Asymptotic expansion for very negative z following (26.2.12)
            // on page 408 in M. Abramowitz and A. Stegun,
            // Pocketbook of Mathematical Functions, ISBN 3-87144818-4.
            Real sum=1.0, zsqr=z*z, i=1.0, g=1.0, x, y,
                 a=QL_MAX_REAL, lasta;
            do {
                lasta=a;
                x = (4.0*i-3.0)/zsqr;
                y = x*((4.0*i-1)/zsqr);
                a = g*(x-y);
                sum -= a;
                g *= y;
                ++i;
                a = std::fabs(a);
            } while (lasta>a && a>=std::fabs(sum*QL_EPSILON));
            result = -gaussian_(z)/z*sum;
        }
        return result;
    }

    // #if !defined(QL_PATCH_SOLARIS)
    // const CumulativeNormalDistribution InverseCumulativeNormal::f_;
    // #endif

    inline Real InverseCumulativeNormal::tail_value(Real x) {
        if (x <= 0.0 || x >= 1.0) {
            // try to recover if due to numerical error
            if (close_enough(x, 1.0)) {
                return QL_MAX_REAL; // largest value available
            } else if (std::fabs(x) < QL_EPSILON) {
                return QL_MIN_REAL; // largest negative value available
            } else {
                QL_FAIL("InverseCumulativeNormal(" << x
                        << ") undefined: must be 0 < x < 1");
            }
        }

        Real z;
        if (x < x_low_()) {
            // Rational approximation for the lower region 0<x<u_low
            z = std::sqrt(-2.0*std::log(x));
            z = (((((c1_()*z+c2_())*z+c3_())*z+c4_())*z+c5_())*z+c6_()) /
                ((((d1_()*z+d2_())*z+d3_())*z+d4_())*z+1.0);
        } else {
            // Rational approximation for the upper region u_high<x<1
            z = std::sqrt(-2.0*std::log(1.0-x));
            z = -(((((c1_()*z+c2_())*z+c3_())*z+c4_())*z+c5_())*z+c6_()) /
                ((((d1_()*z+d2_())*z+d3_())*z+d4_())*z+1.0);
        }

        return z;
    }

    inline Real MoroInverseCumulativeNormal::operator()(Real x) const {
        QL_REQUIRE(x > 0.0 && x < 1.0,
                   "MoroInverseCumulativeNormal(" << x
                   << ") undefined: must be 0<x<1");

        Real result;
        Real temp=x-0.5;

        if (std::fabs(temp) < 0.42) {
            // Beasley and Springer, 1977
            result=temp*temp;
            result=temp*
                (((a3_()*result+a2_())*result+a1_())*result+a0_()) /
                ((((b3_()*result+b2_())*result+b1_())*result+b0_())*result+1.0);
        } else {
            // improved approximation for the tail (Moro 1995)
            if (x<0.5)
                result = x;
            else
                result=1.0-x;
            result = std::log(-std::log(result));
            result = c0_()+result*(c1_()+result*(c2_()+result*(c3_()+result*
                                   (c4_()+result*(c5_()+result*(c6_()+result*
                                                       (c7_()+result*c8_())))))));
            if (x<0.5)
                result=-result;
        }

        return average_ + result*sigma_;
    }

    inline MaddockInverseCumulativeNormal::MaddockInverseCumulativeNormal(
        Real average, Real sigma)
    : average_(average), sigma_(sigma) {}

    inline Real MaddockInverseCumulativeNormal::operator()(Real x) const {
        return boost::math::quantile(
            boost::math::normal_distribution<Real>(average_, sigma_), x);
    }

    inline MaddockCumulativeNormal::MaddockCumulativeNormal(
        Real average, Real sigma)
    : average_(average), sigma_(sigma) {}

    inline Real MaddockCumulativeNormal::operator()(Real x) const {
        return boost::math::cdf(
            boost::math::normal_distribution<Real>(average_, sigma_), x);
    }

}

#endif


/*
 * PolynomialSpline.hpp
 *
 *  Created on: Mar 7, 2017
 *      Author: Dario Bellicoso
 */

#pragma once

// eigen
#include <Eigen/Core>

// curves
#include "curves/polynomial_splines_traits.hpp"

// stl
#include <numeric>

namespace curves {

/*!
 *  This class is the implementation of a scalar polynomial spline s(t) function of a scalar t.
 *  The spline is define as
 *    s(t) = an*t^n + ... + a1*t + a0 = sum(ai*t^i)
 *
 *  The spline coefficients are stored in a standard container as
 *    alpha = [an ... a1 a0]^T
 *
 *  The spline can also be evaluated as:
 *    s(t) = tau^T * alpha
 *
 *  where the vector tau (referred to as time vector in the comments) is define as
 *    tau = [t^n ... t^2 t 1]^T
 */
template <int splineOrder_>
class PolynomialSpline {
 public:

  static constexpr unsigned int splineOrder = splineOrder_;
  static constexpr unsigned int coefficientCount = splineOrder + 1;

  using SplineImplementation = spline_traits::spline_rep<double, splineOrder>;
  using SplineCoefficients = typename SplineImplementation::SplineCoefficients;
  using EigenTimeVectorType = Eigen::Matrix<double, 1, coefficientCount>;
  using EigenCoefficientVectorType = Eigen::Matrix<double, coefficientCount, 1>;

  PolynomialSpline() :
    duration_(0.0),
    didEvaluateCoeffs_(false),
    coefficients_()
  {

  }

  template<typename SplineCoeff_>
  PolynomialSpline(SplineCoeff_&& coefficients, double duration) :
    duration_(duration),
    didEvaluateCoeffs_(true),
    coefficients_(std::forward<SplineCoeff_>(coefficients))
  {

  }

  explicit PolynomialSpline(const SplineOptions& options) : duration_(options.tf_) {
    computeCoefficients(options);
  }

  explicit PolynomialSpline(SplineOptions&& options) : duration_(options.tf_) {
    computeCoefficients(std::move(options));
  }

  virtual ~PolynomialSpline() = default;

  PolynomialSpline(PolynomialSpline &&) = default;
  PolynomialSpline& operator=(PolynomialSpline &&) = default;

  PolynomialSpline(const PolynomialSpline&) = default;
  PolynomialSpline& operator=(const PolynomialSpline&) = default;

  //! Get the coefficients of the spline.
  const SplineCoefficients& getCoefficients() const {
    return coefficients_;
  }

  //! Get the coefficients of the spline.
  SplineCoefficients* getCoefficientsPtr() {
    return &coefficients_;
  }

  //! Compute the coefficients of the spline.
  template<typename SplineOptionsType_>
  bool computeCoefficients(SplineOptionsType_&& options) {
    duration_ = options.tf_;
    return SplineImplementation::compute(std::forward<SplineOptionsType_>(options), coefficients_);
  }

  //! Set the coefficients and the duration of the spline.
  void setCoefficientsAndDuration(const SplineCoefficients& coefficients, double duration) {
    coefficients_ = coefficients;
    duration_ = duration;
  }

  //! Get the spline evaluated at time tk.
  constexpr double getPositionAtTime(double tk) const {
    return std::inner_product(coefficients_.begin(), coefficients_.end(),
                              SplineImplementation::tau(tk).begin(), 0.0);
  }

  //! Get the first derivative of the spline evaluated at time tk.
  constexpr double getVelocityAtTime(double tk) const {
    return std::inner_product(coefficients_.begin(), coefficients_.end(),
                              SplineImplementation::dtau(tk).begin(), 0.0);
  }

  //! Get the second derivative of the spline evaluated at time tk.
  constexpr double getAccelerationAtTime(double tk) const {
    return std::inner_product(coefficients_.begin(), coefficients_.end(),
                              SplineImplementation::ddtau(tk).begin(), 0.0);
  }

  //! Get the time vector evaluated at time tk.
  static inline void getTimeVector(Eigen::Ref<EigenTimeVectorType> timeVec, const double tk) {
    timeVec = Eigen::Map<EigenTimeVectorType>(SplineImplementation::tau(tk).data());
  }

  //! Get the time vector evaluated at time tk.
  template<typename Derived>
  static inline void getTimeVector(Eigen::MatrixBase<Derived> const & timeVec, const double tk) {
    assert(timeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           timeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(timeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::tau(tk)).data());
  }

  //! Get the time vector evaluated at time tk and add it to the input vector.
  template<typename Derived>
  static inline void addTimeVector(Eigen::MatrixBase<Derived> const & timeVec, const double tk) {
    assert(timeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           timeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(timeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::tau(tk)).data());
  }

  //! Get the first derivative of the time vector evaluated at time tk.
  static inline void getDTimeVector(Eigen::Ref<EigenTimeVectorType> dtimeVec, const double tk) {
    dtimeVec = Eigen::Map<EigenTimeVectorType>(SplineImplementation::dtau(tk).data());
  }

  //! Get the first derivative of the time vector evaluated at time tk.
  template<typename Derived>
  static inline void getDiffTimeVector(Eigen::MatrixBase<Derived> const & dtimeVec, const double tk) {
    assert(dtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           dtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(dtimeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtau(tk)).data());
  }

  //! Get the first derivative of the time vector evaluated at time tk and add it to the input vector.
  template<typename Derived>
  static inline void addDiffTimeVector(Eigen::MatrixBase<Derived> const & dtimeVec, const double tk) {
    assert(dtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           dtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(dtimeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtau(tk)).data());
  }

  //! Get the second derivative of the time vector evaluated at time tk.
  static inline void getDDTimeVector(Eigen::Ref<EigenTimeVectorType> ddtimeVec, const double tk) {
    ddtimeVec = Eigen::Map<EigenTimeVectorType>(SplineImplementation::ddtau(tk).data());
  }

  //! Get the second derivative of the time vector evaluated at time tk.
  template<typename Derived>
  static inline void getDDiffTimeVector(Eigen::MatrixBase<Derived> const & ddtimeVec, const double tk) {
    assert(ddtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           ddtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(ddtimeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtau(tk)).data());
  }

  //! Get the second derivative of the time vector evaluated at time tk and add it to the input vector.
  template<typename Derived>
  static inline void addDDiffTimeVector(Eigen::MatrixBase<Derived> const & ddtimeVec, const double tk) {
    assert(ddtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           ddtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(ddtimeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::ddtau(tk)).data());
  }

  //! Get the time vector evaluated at zero.
  static inline void getTimeVectorAtZero(Eigen::Ref<EigenTimeVectorType> timeVec) {
    timeVec = Eigen::Map<const EigenTimeVectorType>((SplineImplementation::tauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void getTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & timeVec) {
    assert(timeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           timeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(timeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::tauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void addTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & timeVec) {
    assert(timeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           timeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(timeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::tauZero).data());
  }

  //! Get the first derivative of the time vector evaluated at zero.
  static inline void getDTimeVectorAtZero(Eigen::Ref<EigenTimeVectorType> dtimeVec) {
    dtimeVec = Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void getDiffTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & dtimeVec) {
    assert(dtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           dtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(dtimeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void addDiffTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & dtimeVec) {
    assert(dtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           dtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(dtimeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::dtauZero).data());
  }

  //! Get the second derivative of the time vector evaluated at zero.
  static inline void getDDTimeVectorAtZero(Eigen::Ref<EigenTimeVectorType> ddtimeVec) {
    ddtimeVec = Eigen::Map<const EigenTimeVectorType>((SplineImplementation::ddtauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void getDDiffTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & ddtimeVec) {
    assert(ddtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           ddtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(ddtimeVec) =
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::ddtauZero).data());
  }

  //! Get the time vector evaluated at zero.
  template<typename Derived>
  static inline void addDDiffTimeVectorAtZero(
      Eigen::MatrixBase<Derived> const & ddtimeVec) {
    assert(ddtimeVec.rows() == EigenTimeVectorType::RowsAtCompileTime &&
           ddtimeVec.cols() == EigenTimeVectorType::ColsAtCompileTime);
    // https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
    const_cast<Eigen::MatrixBase<Derived>&>(ddtimeVec) +=
        Eigen::Map<const EigenTimeVectorType>((SplineImplementation::ddtauZero).data());
  }

  //! Get the duration of the spline in seconds.
  double getSplineDuration() const {
    return duration_;
  }

 protected:
  //! The duration of the spline in seconds.
  double duration_;

  //! True if the coefficents were computed at least once.
  bool didEvaluateCoeffs_;

  /*
   * s(t) = an*t^n + ... + a1*t + a0
   * splineCoeff_ = [an ... a1 a0]
   */
  SplineCoefficients coefficients_;
};

} /* namespace */


#include <Rcpp.h>
#include <iostream>
#include <fstream>
#include <cmath>
#include <igl/volume.h>
#include <Eigen/Core>
using namespace Rcpp;

  // [[Rcpp::export]]
double mesh_volume(NumericMatrix Vi, NumericMatrix Fi) {

  int V_nrow = Vi.nrow(), F_nrow = Fi.nrow();
  int V_ncol = Vi.ncol(), F_ncol = Fi.ncol();

  // std::cout << VA_nrow << "\t" << VA_ncol << "\t" << VB_nrow << "\t" << VB_ncol << "\t" << FA_nrow << "\t" << FA_ncol << "\t" << FB_nrow << "\t" << FB_ncol << "\n" ;

  Eigen::MatrixXd V(V_nrow,V_ncol);
  Eigen::MatrixXi F(F_nrow,F_ncol);

  for(int i=0; i < V_nrow; i++){
    for(int j=0; j< V_ncol; j++){
      V(i,j) = Vi(i,j);
    }
  }

  for(int i=0; i < F_nrow; i++){
    for(int j=0; j< F_ncol; j++){
      F(i,j) = Fi(i,j);
    }
  }

  Eigen::MatrixXd V2(V.rows() + 1, V.cols());
  V2.topRows(V.rows()) = V;
  V2.bottomRows(1).setZero();
  Eigen::MatrixXi T(F.rows(), 4);
  T.leftCols(3) = F;
  T.rightCols(1).setConstant(V.rows());
  Eigen::VectorXd vol;
  igl::volume(V2, T, vol);

  return std::abs( vol.sum());
  }


#pragma once

#include "../PolynomialBasisGen.hh"
#include "RBFKernel.hh"
#include "FiniteDifferentiator.hh"
#include <Eigen/Dense>
#include <boost/tuple/tuple.hpp>
#include <boost/static_assert.hpp>
#include <vector>

namespace kt84 {

template <int _DimIn, int _DimOut, class _RBFKernel_Core, int _DegreePolynomial>
struct HermiteRBF
    : public FiniteDifferentiator<HermiteRBF<_DimIn, _DimOut, _RBFKernel_Core, _DegreePolynomial>, _DimIn, _DimOut>
{
    enum {
        DimIn  = _DimIn,
        DimOut = _DimOut,
        DegreePolynomial = _DegreePolynomial,
    };

    typedef Eigen::Matrix<double, DimIn , 1> Point;
    typedef Eigen::Matrix<double, DimOut, 1> Value;
    typedef Eigen::Matrix<double, DimOut, DimIn> Gradient;
    typedef PolynomialBasisGen<DimIn, DegreePolynomial> PolynomialBasisGen;
    typedef RBFKernel_Bivariate<DimIn, _RBFKernel_Core> Kernel;
    typedef boost::tuple<Point, Value, Gradient> Constraint;

    BOOST_STATIC_ASSERT(Kernel::GradientAlwaysDefined);

    std::vector<Constraint> constraints;
    Kernel kernel;
    Eigen::Matrix<double, -1, DimOut> weights;
    Eigen::MatrixXd A_matrix;
    Eigen::ColPivHouseholderQR<Eigen::MatrixXd> A_factorized;

    void clear_constraints() {
        constraints.clear();
    }
    void add_constraint(const Point& point, const Value& value, const Gradient& gradient) {
        constraints.push_back(Constraint(point, value, gradient));
    }
    void factorize() {
        const int P = PolynomialBasisGen::DimOut;
        const int D = 1 + DimIn;
        const size_t n = constraints.size();
        const int m = D * n + P;
        A_matrix = Eigen::MatrixXd::Zero(m, m);
        for (size_t i = 0; i < n; ++i) {
            const Point& point_i = constraints[i].get<0>();
            // rbf part
            for (size_t j = 0; j < n; ++j) {       // note that A is not symmetric
                const Point& point_j = constraints[j].get<0>();
                // make submatrix
                Eigen::Matrix<double, D, D> A_sub;
                A_sub.setZero();
                A_sub(0, 0) = kernel(point_i, point_j);
                A_sub.block<1, DimIn>(0, 1) = kernel.gradient(point_i, point_j);
                A_sub.block<DimIn, 1>(1, 0) = A_sub.block<1, DimIn>(0, 1).transpose();
                A_sub.block<DimIn, DimIn>(1, 1) = kernel.hessian(point_i, point_j);
                // insert submatrix
                A_matrix.block<D, D>(D * i, D * j) = A_sub;
            }
            // polynomial part
            A_matrix.block<P, D>(D * n, D * i) <<
                PolynomialBasisGen::basis(point_i),
                PolynomialBasisGen::gradient(point_i);
            A_matrix.block<D, P>(D * i, D * n) = A_matrix.block<P, D>(D * n, D * i).transpose();
        }
        A_factorized.compute(A_matrix);         // factorize
    }
    void solve() {
        const int P = PolynomialBasisGen::DimOut;
        const int D = 1 + DimIn;
        const size_t n = constraints.size();
        const int m = D * n + P;
        Eigen::Matrix<double, -1, DimOut> b;
        b.setZero(m, DimOut);
        // constraint part
        for (size_t i = 0; i < n; ++i) {
            const Value& value_i = constraints[i].get<1>();
            const Gradient& gradient_i = constraints[i].get<2>();
            b.block<D, DimOut>(D * i, 0).transpose() << value_i, gradient_i;
        }
        // polynomial part is just 0
        weights = A_factorized.solve(b);        // solve
    }
    void factorize_and_solve() {
        factorize();
        solve();
    }
    Value operator()(const Point& point) const {
        const int P = PolynomialBasisGen::DimOut;
        const int D = 1 + DimIn;
        Value result = Value::Zero();
        for (size_t i = 0; i < constraints.size(); ++i) {
            const Point& point_i = constraints[i].get<0>();
            // first (value) rbf part
            result += kernel(point, point_i) * weights.row(D * i).transpose();
            // second (gradient) rbf part
            result += (kernel.gradient(point, point_i) * weights.block<DimIn, DimOut>(D * i + 1, 0)).transpose();
        }
        // polynomial part
        PolynomialBasisGen::Basis basis = PolynomialBasisGen::basis(point);
        result += (basis.transpose() * weights.bottomRows(P)).transpose();
        return result;
    }
    Gradient gradient(const Point& point) const {
        const int P = PolynomialBasisGen::DimOut;
        Gradient result = Gradient::Zero();
        // rbf part
        for (size_t i = 0; i < constraints.size(); ++i) {
            const Point& point_i = constraints[i].get<0>();
            const int D = 1 + DimIn;
            // first (value) rbf part
            result += weights.row(D * i).transpose() * kernel.gradient(point, point_i);
            // second (gradient) rbf part
            result += weights.block<DimIn, DimOut>(D * i + 1, 0).transpose() * kernel.hessian(point, point_i);
        }
        // polynomial part
        PolynomialBasisGen::Gradient b_gradient = PolynomialBasisGen::gradient(point);
        result += weights.bottomRows(P).transpose() * b_gradient;
        return result;
    }
};

}


#include "complexErf.hpp"

#include <ql/math/comparison.hpp>

#include <boost/math/special_functions/erf.hpp>

namespace QuantLib {
std::complex<double> erf(const std::complex<double>& z, const std::size_t order) {
    const double x = z.real();
    const double y = z.imag();
    double erfr = boost::math::erf(x);
    double erfi = 0.0;
    const double emxs = std::exp(-x * x);
    if (!close_enough(x, 0.0)) {
        erfr += emxs / (2.0 * M_PI * x) * (1.0 - cos(2.0 * x * y));
        erfi += emxs / (2.0 * M_PI * x) * sin(2.0 * x * y);
    } else {
        erfi += y / (M_PI);
    }
    double rr = 0.0, ri = 0.0;
    for (int n = 1; n <= order; ++n) {
        double nd = static_cast<double>(n);
        rr += exp(-0.25 * nd * nd) / (nd * nd + 4.0 * x * x) *
              (2.0 * x - 2.0 * x * cosh(nd * y) * cos(2.0 * x * y) + nd * sinh(n * y) * sin(2.0 * x * y));
        ri += exp(-0.25 * nd * nd) / (nd * nd + 4.0 * x * x) *
              (2.0 * x * cosh(nd * y) * sin(2.0 * x * y) + nd * sinh(nd * y) * cos(2.0 * x * y));
    }
    rr *= 2.0 / M_PI * emxs;
    ri *= 2.0 / M_PI * emxs;
    return std::complex<double>(erfr + rr, erfi + ri);
}
} // namespace QuantLib


/*
 This program is free software; you can redistribute it and/or modify it under
 the terms of the European Union Public Licence - EUPL v.1.1 as published by
 the European Commission.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the European Union Public Licence - EUPL v.1.1
 for more details.

 You should have received a copy of the European Union Public Licence - EUPL v.1.1
 along with this program.

 Further information about the European Union Public Licence - EUPL v.1.1 can
 also be found on the world wide web at http://ec.europa.eu/idabc/eupl

*/

/*
 ------ Copyright (C) 2011 STA Steering Board (space.trajectory.analysis AT gmail.com) ----
*/

//------------------ Author: Catarina Silva  -------------------------------------------------
// ------------------ E-mail: (catsilva20@gmail.com) ------------------------------------------
// Patched by Guillermo to correct errors, July 2011
// Patched by Guillermo to allow compilation in Linux, August 2011

#include "attitudetransformations.h"

#include "Astro-Core/RotationState.h"
#include "Astro-Core/stamath.h"
#include "Astro-Core/stamath.h"
#include <Eigen/Core>
#include <Eigen/Geometry>

#include <QDebug>
#include <QMessageBox>

// Sets all the transformations between quaternions, Euler angles and Direction cosine matrix
// The following Euler sequences will be implemented: 123, 321, 313

//----------------------------------------------------------------------------------------------------------------------
// The quaternions are considered to have
// the following form: q = w + xi + yj + zk = q4 + q1i + q2j + q3k, with q4 being the real part, and q1, q2 and q3
// the imaginary part.
// Throughout the code, PHI is considered to be the first rotation angle, THETA the second rotation angle and PSI the
// third rotation angle.
//-----------------------------------------------------------------------------------------------------------------------
//Euler to Quaternions
/**
  * Converts the input Euler angles and sequence to a DCM
  *
  * @param EulerAngles  the input Euler angles (radians)
  * @param seq1         first entry of the Euler sequence
  * @param seq2         second entry of the Euler sequence
  * @param seq3         third entry of the Euler sequence
  *
  * @return the Quaternions
  */
Quaterniond ToQuaternions(const Vector3d EulerAngles,
                          int seq1,
                          int seq2,
                          int seq3)
{
    //Euler angles (phi, theta, psi)
    double phi= sta::degToRad(EulerAngles[0]);
    double theta = sta::degToRad(EulerAngles[1]);
    double psi = sta::degToRad(EulerAngles[2]);

    // SEQUENCE 321
    if (seq1 == 3 && seq2 == 2 && seq3 == 1)
    {
        Quaterniond quaternion = Quaterniond(AngleAxis<double> (phi,   Vector3d::UnitZ())*
                                             Quaterniond(AngleAxis<double> (theta, Vector3d::UnitY()))*
                                             Quaterniond(AngleAxis<double> (psi,   Vector3d::UnitX())));

        return quaternion;
    }

    // SEQUENCE 123
    if (seq1 == 1 && seq2 == 2 && seq3 == 3)
    {

        Quaterniond quaternion = Quaterniond(AngleAxis<double> (phi,   Vector3d::UnitX())*
                                             Quaterniond(AngleAxis<double> (theta, Vector3d::UnitY()))*
                                             Quaterniond(AngleAxis<double> (psi,   Vector3d::UnitZ())));

        return quaternion;
    }

    // SEQUENCE 313
    if(seq1 == 3 && seq2 == 1 && seq3 == 3)
    {

        Quaterniond quaternion = Quaterniond(AngleAxis<double> (phi,   Vector3d::UnitZ())*
                                             Quaterniond(AngleAxis<double> (theta, Vector3d::UnitX()))*
                                             Quaterniond(AngleAxis<double> (psi,   Vector3d::UnitZ())));
        return quaternion;

    }

}

//Quaternions to Euler angles
/**
  * Converts the input quaternions to a set of Euler angles, using the Euler sequence provided
  *
  * @param quaternion   the input quaternions
  * @param seq1         first entry of the Euler sequence
  * @param seq2         second entry of the Euler sequence
  * @param seq3         third entry of the Euler sequence
  *
  * @return the Euler angles (radians)
  */
Vector3d ToEulerAngles(Quaterniond quaternion,
                       int seq1,
                       int seq2,
                       int seq3)
{
    double theta1, theta2, theta3, a, b, c;
    Vector3d finalEulerAngles;

    //Transform the initial quaternions in the direction cosine matrix, using Eigen::Geometry capabilities.
//     Matrix3d R = quaternion.toRotationMatrix();

        double q1 = quaternion.coeffs().coeffRef(0);
        double q2 = quaternion.coeffs().coeffRef(1);
        double q3 = quaternion.coeffs().coeffRef(2);
        double q4 = quaternion.coeffs().coeffRef(3);

        double rotationMatrix_coeff[9]=
        {
            (1-2*(q2*q2+q3*q3)),   2*(q1*q2-q3*q4),    2*(q1*q3+q2*q4),
            2*(q2*q1+q3*q4),      1-2*(q1*q1+q3*q3),   2*(q2*q3-q1*q4),
            2*(q3*q1-q2*q4),        2*(q3*q2+q1*q4),   (1-2*(q1*q1+q2*q2))
        };

       Matrix3d R(rotationMatrix_coeff);

    //Transform the direction cosine matrix in the Euler angles for the three sequences.
    // SEQUENCE 321
    if (seq1 == 3 && seq2 == 2 && seq3 == 1)
    {
        a = R(0,1)/R(0,0);
        theta1 = atan(a);
        theta2 = asin(-R(0,2));
        b = R(2,0)*sin(theta1) - R(2,1)*cos(theta1);
        c = -R(1,0)*sin(theta1) + R(1,1)*cos(theta1);
        theta3 = atan(b/c);
    }
    // SEQUENCE 123
    else if (seq1 == 1 && seq2 == 2 && seq3 == 3)
    {
        a = -R(2,1)/R(2,2);
        theta1 = atan(a);
        theta2 = asin(R(2,0));
        b = R(0,2)*sin(theta1) + R(0,1)*cos(theta1);
        c = R(1,2)*sin(theta1) + R(1,1)*cos(theta1);
        theta3 = atan(b/c);
    }
    // SEQUENCE 313
    else if (seq1 == 3 && seq2 == 1 && seq3 == 3)
    {
        a = R(2,0)/(-R(2,1));
        theta1 = atan(a);
        theta2 = acos(R(2,2));
        b = -R(1,1)*sin(theta1) - R(1,0)*cos(theta1);
        c = R(0,1)*sin(theta1) + R(0,0)*cos(theta1);
        theta3 = atan(b/c);
    }
    else
    {
        theta1= 0.0;
        theta2 = 0.0;
        theta3 = 0.0;
    }

    finalEulerAngles(0) = theta1;
    finalEulerAngles(1) = theta2;
    finalEulerAngles(2) = theta3;

    return finalEulerAngles;
}

//Body rates to Euler angle rates
/**
  * Converts the input angular velocity to a set of Euler angles rates, using the Euler sequence provided
  *
  * @param angVel       the input angular velocity (radians/seconds)
  * @param EulerAngles  the input Euler angles (radians)
  * @param seq1         first entry of the Euler sequence
  * @param seq2         second entry of the Euler sequence
  * @param seq3         third entry of the Euler sequence
  *
  * @return             the Euler angle rates representation (radians/second)
  */
Vector3d ToEulerAngleRates(const Vector3d angVel,
                           const Vector3d EulerAngles,
                           int seq1,
                           int seq2,
                           int seq3)
{
    //Convert the Euler angles from degress to radians
    //double phi = sta::degToRad(EulerAngles[0]); // Guillermo
    double theta = sta::degToRad(EulerAngles[1]);
    double psi = sta::degToRad(EulerAngles[2]);

    // we need to check the singularities. theta = pi/2 there's a singularity
    bool singularity = false;

    Vector3d finalEulerRates; // Guillermo
    finalEulerRates.setZero();

    // SEQUENCE 321
    if (seq1 == 3 && seq2 == 2 && seq3 == 1)
    {
        if(cos(theta)==0)
            singularity = true;
        else
        {
            static double MatrixCoeffs[9] = {
                0.0,    sin(psi)/cos(theta),              cos(psi)/cos(theta),
                0.0,    cos(psi),                         -sin(psi),
                1.0,   (sin(psi)*sin(theta))/cos(theta),  (cos(psi)*sin(theta))/cos(theta)
            };
            static const Matrix3d Matrix(MatrixCoeffs);
            finalEulerRates = Matrix*angVel;
        }
    }

    // SEQUENCE 123
    if (seq1 == 1 && seq2 == 2 && seq3 == 3)
    {
        if(cos(theta)==0)
            singularity = true;
        else
        {
            static double MatrixCoeffs[9] = {
                cos(psi)/cos(theta),                    -sin(psi)/cos(theta),               0.0,
                sin(psi),                               cos(psi),                           0.0,
                (-cos(psi)*sin(theta))/cos(theta),      (sin(psi)*sin(theta))/cos(theta),   1.0
            };
            static const Matrix3d Matrix(MatrixCoeffs);
            finalEulerRates = Matrix*angVel;
        }
    }

    // SEQUENCE 313
    if (seq1 == 3 && seq2 == 1 && seq3 == 3)
    {
        if(sin(theta)==0)
            singularity = true;
        else
        {
            static double MatrixCoeffs[9] = {
                sin(psi)/sin(theta),                  cos(psi)/sin(theta),                0.0,
                cos(psi),                             -sin(psi),                          0.0,
                -(sin(psi)*cos(theta))/sin(theta),    -(cos(psi)*cos(theta))/sin(theta),    1.0
            };
            static const Matrix3d Matrix(MatrixCoeffs);
            finalEulerRates = Matrix*angVel;
        }
    }

    if (singularity)
    {
        //throw an exception to user
        QMessageBox EulerSingularity;
        //EulerSingularity.setIcon();
        EulerSingularity.setText("A singularity in the Euler angles has occurred. Value of angle rates set to (0,0,0). Do you want to continue?");
        EulerSingularity.setStandardButtons(QMessageBox::Ignore | QMessageBox::Abort);
        EulerSingularity.setDefaultButton(QMessageBox::Abort);
        EulerSingularity.exec();
        finalEulerRates << 0, 0, 0;  // Guillermo
    }

    return finalEulerRates;
}

//Euler angle rates to Body rates
/**
  * Converts the input Euler angle rates to an angular velocity, using the Euler sequence provided
  *
  * @param EulerRates   the input Euler rates (radians/seconds)
  * @param EulerAngles  the input Euler angles (radians)
  * @param seq1         first entry of the Euler sequence
  * @param seq2         second entry of the Euler sequence
  * @param seq3         third entry of the Euler sequence
  *
  * @return             the angular velocity (radians/second)
  */
Vector3d ToAngularVelocity(const Vector3d EulerRates,
                           const Vector3d EulerAngles,
                           int seq1,
                           int seq2,
                           int seq3)
{
    //Convert the Euler angles from degress to radians
    //double phi = sta::degToRad(EulerAngles[0]);
    double theta = sta::degToRad(EulerAngles[1]);
    double psi = sta::degToRad(EulerAngles[2]);
    Vector3d finalAngVel;

    // SEQUENCE 321
    if(seq1 == 3 && seq2 == 2 && seq3 == 1)
    {
        static double MatrixCoeffs[9] = {
            -sin(theta),                  0,          1,
            sin(psi)*cos(theta),          cos(psi),   0,
            cos(psi)*cos(theta),         -sin(psi),   0
        };
        static const Matrix3d Matrix(MatrixCoeffs);
        finalAngVel = Matrix * EulerRates;
    }

    // SEQUENCE 123
    if(seq1 == 1 && seq2 == 2 && seq3 == 3)
    {
        static double MatrixCoeffs[9] = {
            cos(psi)*cos(theta),      sin(psi),   0.0,
            -sin(psi)*cos(theta),     cos(psi),   0.0,
            sin(theta),               0.0,        1.0
        };
        static const Matrix3d Matrix(MatrixCoeffs);
        finalAngVel = Matrix * EulerRates;
    }

    // SEQUENCE 313
    if(seq1 == 3 && seq2 == 1 && seq3 == 3)
    {
        static double MatrixCoeffs[9] = {
            sin(psi)*sin(theta),        cos(psi),       0.0,
            cos(psi)*sin(theta),        -sin(psi),      0.0,
            cos(theta),                 0.0,            1.0
        };
        static const Matrix3d Matrix(MatrixCoeffs);
        finalAngVel = Matrix * EulerRates;
    }

    return finalAngVel;
}

//------------------------------------------------------------------------------------------------------------
// These transformations were taken from: "Space vehicles dynamics and control", Bong Wie, AIAA Education Series
//------------------------------------------------------------------------------------------------------------

//Quaternion rates to body rates
Vector3d ToAngularVelocity(Eigen::Quaterniond quaternion,
                           Eigen::Quaterniond initQuatRates)
{
    // q = q4 + q1i + q2j + q3k
    double q1 = quaternion.coeffs().coeffRef(0);
    double q2 = quaternion.coeffs().coeffRef(1);
    double q3 = quaternion.coeffs().coeffRef(2);
    double q4 = quaternion.coeffs().coeffRef(3);

    double q1_Dot = initQuatRates.coeffs().coeffRef(0);
    double q2_Dot = initQuatRates.coeffs().coeffRef(1);
    double q3_Dot = initQuatRates.coeffs().coeffRef(2);
    double q4_Dot = initQuatRates.coeffs().coeffRef(3);

    //    static const Vector qDot(q1_Dot,q2_Dot,q3_Dot, q4_Dot );

    //    static const Vector3d angularRates = 2*W_q*qDot;
    double angRate_p = 2*(q4*q1_Dot + q3*q2_Dot - q2*q3_Dot - q1*q4_Dot);
    double angRate_q = 2*(-q3*q1_Dot + q4*q2_Dot + q1*q3_Dot - q2*q4_Dot);
    double angRate_r = 2*(q2*q1_Dot - q1*q2_Dot + q4*q3_Dot - q3*q4_Dot);

    Vector3d angularRates(angRate_p,angRate_q,angRate_r);
    return angularRates;

}

//Body rates to quaternion rates
Quaterniond ToQuaternionRates(Eigen::Quaterniond quaternion,
                              Vector3d bodyRates)
{

    double q1 = quaternion.coeffs().coeffRef(0);
    double q2 = quaternion.coeffs().coeffRef(1);
    double q3 = quaternion.coeffs().coeffRef(2);
    double q4 = quaternion.coeffs().coeffRef(3);

    double p = bodyRates[0];
    double q = bodyRates[1];
    double r = bodyRates[2];

    double q1_Dot = 0.5*(q4*p - q3*q + q2*r);
    double q2_Dot = 0.5*(q3*p + q4*q - q1*r);
    double q3_Dot = 0.5*(-q2*p + q1*q + q4*r);
    double q4_Dot = 0.5*(-q1*p - q2*q - q3*r);

    Quaterniond quatRates(q1_Dot, q2_Dot, q3_Dot, q4_Dot);
    return quatRates;
}


#pragma once
#include <future>
#include <iostream>
#include <Eigen/Dense>
#include <limits.h>
#include "Data.hpp"
#include "tsne/tsne.h"

//Single class for data projection, differnet methods can be set in the constructor
//When created the data is projected in a separate thread
//On completion the "projected" member is set to true
//Call wait on the future object to sync
class DataProjector{
public:
    enum Method{
        PCA,
        TSNE
    };

    struct ProjectionSettings{
        //settings for PCA

        //settings for TSNE
        double perplexity, theta;
        int randSeed, maxIter, stopLyingIter, momSwitchIter;
        bool skipRandomInit;
    };

    DataProjector(const Data& data, int reducedDimensionSize, Method projectionMethod, const ProjectionSettings& settings, std::vector<uint32_t>& indices, std::vector<uint32_t> attributeIndices = {}):data(data), reducedDimensionSize(reducedDimensionSize), projectionMethod(projectionMethod), indices(indices){
        if(attributeIndices.empty()){
            this->attributeIndices.resize(data.columns.size());
            for(uint32_t i = 0; i < indices.size(); ++i) this->attributeIndices[i] = i;
        }
        else this->attributeIndices = attributeIndices;
        this->settings = settings;
        future = std::async(runAsync, this);
    }

    static void runAsync(DataProjector* p){
        p->run();
    }

    void run(){
        switch(projectionMethod){
        case Method::PCA:{
            execPCA();
        } break;
        case Method::TSNE:{
            execTSNE();
        }break;
        }
    }

    Eigen::MatrixXf projectedPoints;
    bool projected = false;
    bool interrupted = false;
    float progress = .0f;
    int reducedDimensionSize;
    std::future<void> future;

protected:
    const Data& data;
    std::vector<uint32_t> attributeIndices, &indices;
    ProjectionSettings settings;
    const float eps = 1e-6;
    Method projectionMethod;
    Eigen::MatrixXf getDataMatrix(){
        //data to eigen matrix
        Eigen::MatrixXf d(indices.size(), attributeIndices.size());
        for(int i = 0; i < indices.size(); ++i){
            for(int  c = 0; c < attributeIndices.size(); ++c){
                d(i,c) = data(indices[i],attributeIndices[c]);
            }
        }
        //zero center and normalize
        Eigen::RowVectorXf meanCols = d.colwise().mean();
        d = d.rowwise() - meanCols;
        Eigen::RowVectorXf mins = d.colwise().minCoeff(), diff = d.colwise().maxCoeff() - mins;
        diff.array() += eps;
        d.array().rowwise() /= diff.array();
        progress = .33f;
        return d;
    }

    void normalizeProjectedPoints(){
        Eigen::RowVectorXf min = projectedPoints.colwise().minCoeff();
        Eigen::RowVectorXf diff = projectedPoints.colwise().maxCoeff() - min;
        projectedPoints.rowwise() -= min;
        projectedPoints.array().rowwise() /= diff.array();
    }

    void execPCA(){
        Eigen::MatrixXf d = getDataMatrix();
        Eigen::BDCSVD<Eigen::MatrixXf> svd(d, Eigen::ComputeThinU | Eigen::ComputeThinV);
        progress = .66f;
        //convert points to pc scores
        auto u = svd.matrixU().real();
        projectedPoints = u * svd.singularValues().real().asDiagonal();
        //drop unused scores and normalizing the points
        projectedPoints.conservativeResize(Eigen::NoChange, reducedDimensionSize);
        normalizeProjectedPoints();
        progress = 1;
        projected = true;
    }

    void execTSNE(){
        // usage of exact algorithm
        if(data.size() - 1 < 3 * settings.perplexity){
            std::cout << "Perplexity too large for the number of data points!" << std::endl;
            return;
        }
        bool exact = settings.theta == .0f;
        if(exact && data.size() * data.size() > INT_MAX){
            std::cout << "Too large dataset for exact computation, use a theta > 0 for approximation" << std::endl;
            progress = 1;
            interrupted = true;
            return;
        }

        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> d = getDataMatrix().cast<double>();
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> y(d.rows(), reducedDimensionSize);

        //checking rowmajorness of d
        //assert(d(0,0) == d.data()[0]);
        //assert(d(0,1) == d.data()[1]);
        //assert(d(0,2) == d.data()[2]);
        //assert(d(1,0) == d.data()[3]);
        //std::cout << d(0,0) << " " << d.data()[0] << std::endl;
        //std::cout << d(0,1) << " " << d.data()[1] << std::endl;
        //std::cout << d(0,2) << " " << d.data()[2] << std::endl;
        //std::cout << d(1,0) << " " << d.data()[3] << std::endl;
        //std::cout << d(2,0) << " " << d.data()[6] << std::endl;

        TSNE::run(d.data(), d.rows(), d.cols(), y.data(), reducedDimensionSize, settings.perplexity, settings.theta, settings.randSeed, settings.skipRandomInit, settings.maxIter, settings.stopLyingIter, settings.momSwitchIter, &progress);
        if(progress == -1){
            interrupted = true;
            return;
        }
        projectedPoints = y.cast<float>();
        normalizeProjectedPoints();
        progress = 1;
        projected = true;
    }
};


// Copyright Christopher Kormanyos 2013.
// Copyright Paul A. Bristow 2013.
// Copyright John Maddock 2013.

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

#ifdef _MSC_VER
#  pragma warning (disable : 4512) // assignment operator could not be generated.
#  pragma warning (disable : 4996) // assignment operator could not be generated.
#endif

#include <iostream>
#include <limits>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <exception>

// Weisstein, Eric W. "Bessel Function Zeros." From MathWorld--A Wolfram Web Resource.
// http://mathworld.wolfram.com/BesselFunctionZeros.html
// Test values can be calculated using [@wolframalpha.com WolframAplha]
// See also http://dlmf.nist.gov/10.21

//[bessel_errors_example_1

/*`[h5 Error messages from 'bad' input]

Another example demonstrates calculating zeros of the Bessel functions
showing the error messages from 'bad' input is handled by throwing exceptions.

To use the functions for finding zeros of the functions we need:
*/
  #include <boost/math/special_functions/bessel.hpp>
  #include <boost/math/special_functions/airy.hpp>

//] [/bessel_errors_example_1]

int main()
{
//[bessel_errors_example_2

/*`[tip It is always wise to place all code using Boost.Math inside try'n'catch blocks;
this will ensure that helpful error messages can be shown when exceptional conditions arise.]

Examples below show messages from several 'bad' arguments that throw a `domain_error` exception.
*/
  try
  { // Try a zero order v.
    float dodgy_root = boost::math::cyl_bessel_j_zero(0.F, 0);
    std::cout << "boost::math::cyl_bessel_j_zero(0.F, 0) " << dodgy_root << std::endl;
    // Thrown exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int):
    // Requested the 0'th zero of J0, but the rank must be > 0 !
  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }

/*`[note The type shown in the error message is the type [*after promotion],
using __precision_policy and __promotion_policy, from `float` to `double` in this case.]

In this example the promotion goes:

# Arguments are `float` and `int`.
# Treat `int` "as if" it were a `double`, so arguments are `float` and `double`.
# Common type is `double` - so that's the precision we want (and the type that will be returned).
# Evaluate internally as `double` for full `float` precision.

See full code for other examples that promote from `double` to `long double`.

Other examples of 'bad' inputs like infinity and NaN are below.
Some compiler warnings indicate that 'bad' values are detected at compile time.
*/

  try
  { // order v = inf
     std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << std::endl;
     double inf = std::numeric_limits<double>::infinity();
     double inf_root = boost::math::cyl_bessel_j_zero(inf, 1);
     std::cout << "boost::math::cyl_bessel_j_zero(inf, 1) " << inf_root << std::endl;
     // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned):
     // Order argument is 1.#INF, but must be finite >= 0 !
  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }

  try
  { // order v = NaN, rank m = 1
     std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << std::endl;
     double nan = std::numeric_limits<double>::quiet_NaN();
     double nan_root = boost::math::cyl_bessel_j_zero(nan, 1);
     std::cout << "boost::math::cyl_bessel_j_zero(nan, 1) " << nan_root << std::endl;
     // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, unsigned):
     // Order argument is 1.#QNAN, but must be finite >= 0 !
  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }

/*`The output from other examples are shown appended to the full code listing.
*/
//] [/bessel_errors_example_2]
  try
  {   // Try a zero rank m.
    std::cout << "boost::math::cyl_neumann_zero(0.0, 0) " << std::endl;
    double dodgy_root = boost::math::cyl_bessel_j_zero(0.0, 0);
    //  warning C4146: unary minus operator applied to unsigned type, result still unsigned.
    std::cout << "boost::math::cyl_neumann_zero(0.0, -1) " << dodgy_root << std::endl;
    //  boost::math::cyl_neumann_zero(0.0, -1) 6.74652e+009
    // This *should* fail because m is unreasonably large.

  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }

  try
  { // m = inf
   std::cout << "boost::math::cyl_bessel_j_zero(0.0, inf) " << std::endl;
   double inf = std::numeric_limits<double>::infinity();
     double inf_root = boost::math::cyl_bessel_j_zero(0.0, inf);
     // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data.
     std::cout << "boost::math::cyl_bessel_j_zero(0.0, inf) " << inf_root << std::endl;
     // Throw exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int):
     // Requested the 0'th zero, but must be > 0 !

  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }

  try
  { // m = NaN
     double nan = std::numeric_limits<double>::quiet_NaN();
     double nan_root = boost::math::airy_ai_zero<double>(nan);
     // warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data.
     std::cout << "boost::math::airy_ai_zero<double>(nan) " << nan_root << std::endl;
     // Thrown exception Error in function boost::math::airy_ai_zero<double>(double,double):
     // The requested rank of the zero is 0, but must be 1 or more !
  }
  catch (std::exception& ex)
  {
    std::cout << "Thrown exception " << ex.what() << std::endl;
  }
 } // int main()

/*
Output:

  Description: Autorun "J:\Cpp\big_number\Debug\bessel_errors_example.exe"
  Thrown exception Error in function boost::math::cyl_bessel_j_zero<double>(double, int): Requested the 0'th zero of J0, but the rank must be > 0 !
  boost::math::cyl_bessel_j_zero(inf, 1)
  Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#INF, but must be finite >= 0 !
  boost::math::cyl_bessel_j_zero(nan, 1)
  Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Order argument is 1.#QNAN, but must be finite >= 0 !
  boost::math::cyl_neumann_zero(0.0, 0)
  Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the 0'th zero of J0, but the rank must be > 0 !
  boost::math::cyl_bessel_j_zero(0.0, inf)
  Thrown exception Error in function boost::math::cyl_bessel_j_zero<long double>(long double, int): Requested the -2147483648'th zero, but the rank must be positive !
  Thrown exception Error in function boost::math::airy_ai_zero<double>(double,double): The requested rank of the zero is 0, but must be 1 or more !

*/


/* @copyright The code is licensed under the MIT License
 *            <https://opensource.org/licenses/MIT>,
 *            Copyright (c) 2020 Christian Eskil Vaugelade Berg
 * @author Christian Eskil Vaugelade Berg
*/
#pragma once

#include <utility>

#include <Eigen/Dense>

namespace orient {

// \brief Calculate quaternion from angle axis
//        Quaternion is expressed as a 4D-vector [w,a,b,c] such that
//        q = w + a*i + b*j + c*k
// \param aa Source angle axis
// \return The quaternion
template<typename Scalar>
Eigen::Matrix<Scalar, 4, 1> quaternionFromAngleAxis(Eigen::Matrix<Scalar, 3, 1> const& aa);

// \brief Calculate quaternion and partial derivatives from angle axis
//        See above for more detail
// \param aa Source angle axis
// \return A pair containg first the quaternion then secondly the Jacobian matrix
template<typename Scalar>
std::pair<Eigen::Matrix<Scalar, 4, 1>, Eigen::Matrix<Scalar, 4, 3>> quaternionFromAngleAxisWD(Eigen::Matrix<Scalar,3, 1> const& aa);

// \brief Calculate rotation matrix from angle axis
// \param aa Source angle axis
// \return Rotation matrix
template<typename Scalar>
Eigen::Matrix<Scalar, 3, 3> rotationMatrixFromAngleAxis(Eigen::Matrix<Scalar,3, 1> const& aa);

// \brief Calculate rotation matrix and partial derivatives from angle axis
// \param aa Source angle axis
// \return A pair containg first the rotation matrix then secondly the Jacobian matrix
template<typename Scalar>
std::pair<Eigen::Matrix<Scalar, 3, 3>, Eigen::Matrix<Scalar, 9, 3>> rotationMatrixFromAngleAxisWD(Eigen::Matrix<Scalar, 3, 1> const& aa);

}

#include <orient/impl/from_angle_axis.hpp>


// Boost.Geometry (aka GGL, Generic Geometry Library)
// QuickBook Example

// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.

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

//[transform_with_strategy
//` Shows how points can be scaled, translated or rotated

#include <iostream>
#include <boost/geometry.hpp>

int main()
{
    namespace trans = boost::geometry::strategy::transform;
    using boost::geometry::dsv;

    typedef boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian> point_type;

    point_type p1(1.0, 1.0);

    // Translate over (1.5, 1.5)
    point_type p2;
    trans::translate_transformer<double, 2, 2> translate(1.5, 1.5);
    boost::geometry::transform(p1, p2, translate);

    // Scale with factor 3.0
    point_type p3;
    trans::scale_transformer<double, 2, 2> scale(3.0);
    boost::geometry::transform(p1, p3, scale);

    // Rotate with respect to the origin (0,0) over 90 degrees (clockwise)
    point_type p4;
    trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(90.0);
    boost::geometry::transform(p1, p4, rotate);

    std::cout
        << "p1: " << dsv(p1) << std::endl
        << "p2: " << dsv(p2) << std::endl
        << "p3: " << dsv(p3) << std::endl
        << "p4: " << dsv(p4) << std::endl;

    return 0;
}

//]

//[transform_with_strategy_output
/*`
Output:
[pre
p1: (1, 1)
p2: (2.5, 2.5)
p3: (3, 3)
p4: (1, -1)
]
*/
//]


// solving A * X = B
// using driver function gesv()
// with c_vector<> & c_matrix<>

//#define BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS
//#define BOOST_NO_FUNCTION_TEMPLATE_ORDERING

//#define BOOST_NUMERIC_BINDINGS_NO_SANITY_CHECK
//#define BOOST_NUMERIC_BINDINGS_NO_STRUCTURE_CHECK

#include <cstddef>
#include <iostream>
#include <boost/numeric/bindings/atlas/cblas.hpp>
#include <boost/numeric/bindings/atlas/clapack.hpp>
#ifndef BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS
#  include <boost/numeric/bindings/traits/ublas_vector2.hpp>
#endif
#include <boost/numeric/bindings/traits/ublas_matrix.hpp>
#include <boost/numeric/ublas/matrix_proxy.hpp>
#include <boost/numeric/ublas/io.hpp>

namespace ublas = boost::numeric::ublas;
namespace atlas = boost::numeric::bindings::atlas;

using std::size_t;
using std::cout;
using std::endl;

typedef ublas::c_matrix<double, 4, 4> m4x4_t;
typedef ublas::c_matrix<double, 3, 3> m3x3_t;
typedef ublas::c_matrix<double, 1, 3> mrhs_t;
typedef ublas::c_vector<double, 5> v5_t;

int main() {

  cout << endl;
  size_t n = 3;

  m4x4_t a (n, n);   // system matrix
  a(0,0) = 1.; a(0,1) = 1.; a(0,2) = 1.;
  a(1,0) = 2.; a(1,1) = 3.; a(1,2) = 1.;
  a(2,0) = 1.; a(2,1) = -1.; a(2,2) = -1.;

  mrhs_t b (1, n);  // right-hand side vector
  b(0,0) = 4.; b(0,1) = 9.; b(0,2) = -2.;

#ifndef BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS
  m3x3_t a2; // for part 2
  a2 = project (a, ublas::range (0,3), ublas::range (0,3));
  v5_t b2 (n);
  b2 = row (b, 0);
#endif

  // part 1:
  cout << "A: " << a << endl;
  cout << "B: " << b << endl;

  atlas::lu_solve (a, b);
  cout << "X: " << b << endl;

  cout << endl;

#ifndef BOOST_NUMERIC_BINDINGS_POOR_MANS_TRAITS
  // part 2:
  cout << "A: " << a2 << endl;
  cout << "B: " << b2 << endl;

  atlas::lu_solve (a2, b2);
  cout << "X: " << b2 << endl;

  cout << endl;
#endif
}


#ifndef STAN_MATH_FWD_SCAL_FUN_FALLING_FACTORIAL_HPP
#define STAN_MATH_FWD_SCAL_FUN_FALLING_FACTORIAL_HPP

#include <stan/math/fwd/core.hpp>

#include <stan/math/prim/scal/fun/falling_factorial.hpp>
#include <boost/math/special_functions/digamma.hpp>

namespace stan {
  namespace math {

    template<typename T>
    inline fvar<T>
    falling_factorial(const fvar<T>& x, const fvar<T>& n) {
      using boost::math::digamma;

      T falling_fact(falling_factorial(x.val_, n.val_));
      return fvar<T>(falling_fact,
                     falling_fact
                     * (digamma(x.val_ + 1) - digamma(x.val_ - n.val_ + 1))
                     * x.d_
                     + falling_fact
                     * digamma(x.val_ - n.val_ + 1) * n.d_);
    }

    template<typename T>
    inline fvar<T>
    falling_factorial(const fvar<T>& x, double n) {
      using boost::math::digamma;

      T falling_fact(falling_factorial(x.val_, n));
      return fvar<T>(falling_fact,
                     falling_fact
                     * (digamma(x.val_ + 1) - digamma(x.val_ - n + 1))
                     * x.d_);
    }

    template<typename T>
    inline fvar<T>
    falling_factorial(double x, const fvar<T>& n) {
      using boost::math::digamma;

      T falling_fact(falling_factorial(x, n.val_));
      return fvar<T>(falling_fact,
                     falling_fact
                     * digamma(x - n.val_ + 1) * n.d_);
    }
  }
}
#endif