//
// 	Copyright (c) 2018, Cem Bassoy, cem.bassoy@gmail.com
// 	Copyright (c) 2019, Amit Singh, amitsingh19975@gmail.com
//
//  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)
//
//  The authors gratefully acknowledge the support of
//  Google and Fraunhofer IOSB, Ettlingen, Germany
//

#include <boost/numeric/ublas/tensor/extents.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
#include "utility.hpp"

BOOST_AUTO_TEST_SUITE(test_static_extents)

struct fixture
{
  template<std::size_t ... e>
  using extents = boost::numeric::ublas::extents<e...>;

  extents<>                 e0      {};
  extents<1>                e1      {};
  extents<1, 1>             e11     {};
  extents<2, 1>             e21     {};
  extents<1, 2>             e12     {};
  extents<2, 3>             e23     {};
  extents<2, 1, 1>          e211    {};
  extents<2, 3, 1>          e231    {};
  extents<1, 2, 3>          e123    {};
  extents<4, 2, 3>          e423    {};
  extents<1, 2, 3, 4>       e1234   {};
  extents<4, 2, 1, 3>       e4213   {};
  extents<1, 2, 3, 4, 1>    e12341  {};
  extents<4, 2, 1, 3, 1>    e42131  {};
  extents<1, 4, 2, 1, 3, 1> e142131 {};
};

BOOST_FIXTURE_TEST_CASE(test_extents_static_ctor, fixture,
                        *boost::unit_test::label("extents_static") *boost::unit_test::label("ctor"))
{

  namespace ublas = boost::numeric::ublas;

  BOOST_CHECK(  ublas::empty(     e0));
  BOOST_CHECK(! ublas::empty(     e1));
  BOOST_CHECK(! ublas::empty(    e11));
  BOOST_CHECK(! ublas::empty(    e12));
  BOOST_CHECK(! ublas::empty(    e21));
  BOOST_CHECK(! ublas::empty(    e23));
  BOOST_CHECK(! ublas::empty(   e211));
  BOOST_CHECK(! ublas::empty(   e123));
  BOOST_CHECK(! ublas::empty(   e423));
  BOOST_CHECK(! ublas::empty(  e1234));
  BOOST_CHECK(! ublas::empty(  e4213));
  BOOST_CHECK(! ublas::empty(e142131));

  BOOST_CHECK_EQUAL( ublas::size(     e0),0);
  BOOST_CHECK_EQUAL( ublas::size(     e1),1);
  BOOST_CHECK_EQUAL( ublas::size(    e11),2);
  BOOST_CHECK_EQUAL( ublas::size(    e12),2);
  BOOST_CHECK_EQUAL( ublas::size(    e21),2);
  BOOST_CHECK_EQUAL( ublas::size(    e23),2);
  BOOST_CHECK_EQUAL( ublas::size(   e211),3);
  BOOST_CHECK_EQUAL( ublas::size(   e123),3);
  BOOST_CHECK_EQUAL( ublas::size(   e423),3);
  BOOST_CHECK_EQUAL( ublas::size(  e1234),4);
  BOOST_CHECK_EQUAL( ublas::size(  e4213),4);
  BOOST_CHECK_EQUAL( ublas::size(e142131),6);

  BOOST_CHECK_EQUAL( ublas::size_v<decltype(     e0)>,0);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(     e1)>,1);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(    e11)>,2);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(    e12)>,2);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(    e21)>,2);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(    e23)>,2);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(   e211)>,3);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(   e123)>,3);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(   e423)>,3);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(  e1234)>,4);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(  e4213)>,4);
  BOOST_CHECK_EQUAL( ublas::size_v<decltype(e142131)>,6);

}

BOOST_FIXTURE_TEST_CASE(test_extents_static_product, fixture,
                        *boost::unit_test::label("extents_static") *boost::unit_test::label("product"))
{

  namespace ublas = boost::numeric::ublas;

  BOOST_CHECK_EQUAL(ublas::product(     e0),  0);
  //FIXME:  BOOST_CHECK_EQUAL(ublas::product(     e1),  1);
  BOOST_CHECK_EQUAL(ublas::product(    e11),  1);
  BOOST_CHECK_EQUAL(ublas::product(    e12),  2);
  BOOST_CHECK_EQUAL(ublas::product(    e21),  2);
  BOOST_CHECK_EQUAL(ublas::product(    e23),  6);
  BOOST_CHECK_EQUAL(ublas::product(   e211),  2);
  BOOST_CHECK_EQUAL(ublas::product(   e123),  6);
  BOOST_CHECK_EQUAL(ublas::product(   e423), 24);
  BOOST_CHECK_EQUAL(ublas::product(  e1234), 24);
  BOOST_CHECK_EQUAL(ublas::product(  e4213), 24);
  BOOST_CHECK_EQUAL(ublas::product(e142131), 24);

  BOOST_CHECK_EQUAL(ublas::product_v<decltype(     e0)>,  0);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(     e1)>,  1);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(    e11)>,  1);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(    e12)>,  2);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(    e21)>,  2);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(    e23)>,  6);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(   e211)>,  2);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(   e123)>,  6);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(   e423)>, 24);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(  e1234)>, 24);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(  e4213)>, 24);
  BOOST_CHECK_EQUAL(ublas::product_v<decltype(e142131)>, 24);
}

BOOST_FIXTURE_TEST_CASE(test_static_extents_access, fixture,
                        *boost::unit_test::label("extents_static") *boost::unit_test::label("access"))
{
  namespace ublas = boost::numeric::ublas;

  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(     e0)>,0);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(     e1)>,1);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(    e11)>,2);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(    e12)>,2);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(    e21)>,2);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(    e23)>,2);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(   e211)>,3);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(   e123)>,3);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(   e423)>,3);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(  e1234)>,4);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(  e4213)>,4);
  BOOST_REQUIRE_EQUAL( ublas::size_v<decltype(e142131)>,6);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e1),0>), 1);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e11),0>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e11),1>), 1);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e12),0>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e12),1>), 2);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e21),0>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e21),1>), 1);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e23),0>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e23),1>), 3);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e211),0>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e211),1>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e211),2>), 1);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e123),0>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e123),1>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e123),2>), 3);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e423),0>), 4);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e423),1>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e423),2>), 3);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e1234),0>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e1234),1>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e1234),2>), 3);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e1234),3>), 4);

  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e4213),0>), 4);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e4213),1>), 2);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e4213),2>), 1);
  BOOST_CHECK_EQUAL((ublas::get_v<decltype(e4213),3>), 3);

  //FIXME:  BOOST_CHECK_EQUAL(e1 [0], 1);

  BOOST_CHECK_EQUAL(e11[0], 1);
  BOOST_CHECK_EQUAL(e11[1], 1);

  BOOST_CHECK_EQUAL(e12[0], 1);
  BOOST_CHECK_EQUAL(e12[1], 2);

  BOOST_CHECK_EQUAL(e21[0], 2);
  BOOST_CHECK_EQUAL(e21[1], 1);

  BOOST_CHECK_EQUAL(e23[0], 2);
  BOOST_CHECK_EQUAL(e23[1], 3);

  BOOST_CHECK_EQUAL(e211[0], 2);
  BOOST_CHECK_EQUAL(e211[1], 1);
  BOOST_CHECK_EQUAL(e211[2], 1);

  BOOST_CHECK_EQUAL(e123[0], 1);
  BOOST_CHECK_EQUAL(e123[1], 2);
  BOOST_CHECK_EQUAL(e123[2], 3);

  BOOST_CHECK_EQUAL(e423[0], 4);
  BOOST_CHECK_EQUAL(e423[1], 2);
  BOOST_CHECK_EQUAL(e423[2], 3);

  BOOST_CHECK_EQUAL(e1234[0], 1);
  BOOST_CHECK_EQUAL(e1234[1], 2);
  BOOST_CHECK_EQUAL(e1234[2], 3);
  BOOST_CHECK_EQUAL(e1234[3], 4);

  BOOST_CHECK_EQUAL(e4213[0], 4);
  BOOST_CHECK_EQUAL(e4213[1], 2);
  BOOST_CHECK_EQUAL(e4213[2], 1);
  BOOST_CHECK_EQUAL(e4213[3], 3);
}

struct fixture_second
{
  template<std::size_t ... e>
  using extents = boost::numeric::ublas::extents<e...>;

  std::tuple<
    extents<>
    > empty;

  std::tuple<
    //FIXME:    extents<1>,
    extents<1,1>,
    extents<1,1,1>,
    extents<1,1,1,1>
    > scalars;

  std::tuple<
    extents<1,2>,
    extents<2,1>,
    extents<1,2,1>,
    extents<2,1,1>,
    extents<1,4,1,1>,
    extents<5,1,1,1,1>
    > vectors;

  std::tuple<
    extents<2,3>,
    extents<3,2,1>,
    extents<4,4,1,1>,
    extents<6,6,1,1,1,1>
    > matrices;

  std::tuple<
    extents<1,2,3>,
    extents<1,2,3>,
    extents<1,2,3,1>,
    extents<4,2,3>,
    extents<4,2,3,1>,
    extents<4,2,3,1,1>,
    extents<6,6,6,1,1,1>,
    extents<6,6,1,1,1,6>
    > tensors;
};

BOOST_FIXTURE_TEST_CASE(test_static_extents, fixture_second,
                        *boost::unit_test::label("extents_static") *boost::unit_test::label("is_scalar_vector_matrix_tensor")) {

  namespace ublas = boost::numeric::ublas;

  for_each_in_tuple(scalars,[](auto const& /*unused*/, auto const& e){
    BOOST_CHECK(  ublas::is_scalar(e) );
    BOOST_CHECK(  ublas::is_vector(e) );
    BOOST_CHECK(  ublas::is_matrix(e) );
    BOOST_CHECK( !ublas::is_tensor(e) );

    BOOST_CHECK(  ublas::is_scalar_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_vector_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_matrix_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_tensor_v<decltype(e)>);

  });

  for_each_in_tuple(vectors,[](auto const& /*unused*/, auto& e){
    BOOST_CHECK( !ublas::is_scalar(e) );
    BOOST_CHECK(  ublas::is_vector(e) );
    BOOST_CHECK(  ublas::is_matrix(e) );
    BOOST_CHECK( !ublas::is_tensor(e) );

    BOOST_CHECK( !ublas::is_scalar_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_vector_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_matrix_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_tensor_v<decltype(e)>);
  });

  for_each_in_tuple(matrices,[](auto const& /*unused*/, auto& e){
    BOOST_CHECK( !ublas::is_scalar(e) );
    BOOST_CHECK( !ublas::is_vector(e) );
    BOOST_CHECK(  ublas::is_matrix(e) );
    BOOST_CHECK( !ublas::is_tensor(e) );

    BOOST_CHECK( !ublas::is_scalar_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_vector_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_matrix_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_tensor_v<decltype(e)>);
  });

  for_each_in_tuple(tensors,[](auto const& /*unused*/, auto& e){
    BOOST_CHECK( !ublas::is_scalar(e) );
    BOOST_CHECK( !ublas::is_vector(e) );
    BOOST_CHECK( !ublas::is_matrix(e) );
    BOOST_CHECK(  ublas::is_tensor(e) );

    BOOST_CHECK( !ublas::is_scalar_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_vector_v<decltype(e)>);
    BOOST_CHECK( !ublas::is_matrix_v<decltype(e)>);
    BOOST_CHECK(  ublas::is_tensor_v<decltype(e)>);
  });

}

BOOST_FIXTURE_TEST_CASE(test_static_extents_valid, fixture_second,
                        *boost::unit_test::label("extents_extents") *boost::unit_test::label("valid"))
{
  namespace ublas = boost::numeric::ublas;

//FIXME:  BOOST_CHECK(!ublas::is_valid (extents<0>{}) );
//FIXME:  BOOST_CHECK( ublas::is_valid (extents<2>{}) );
//FIXME:  BOOST_CHECK( ublas::is_valid (extents<3>{}) );

  BOOST_CHECK(!ublas::is_valid_v<extents<0>> );
  BOOST_CHECK( ublas::is_valid_v<extents<2>> );
  BOOST_CHECK( ublas::is_valid_v<extents<3>> );

  for_each_in_tuple(scalars  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid (e) ); });
  for_each_in_tuple(vectors  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid (e) ); });
  for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid (e) ); });
  for_each_in_tuple(tensors  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid (e) ); });

  for_each_in_tuple(scalars  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid_v<decltype(e)> ); });
  for_each_in_tuple(vectors  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid_v<decltype(e)> ); });
  for_each_in_tuple(matrices ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid_v<decltype(e)> ); });
  for_each_in_tuple(tensors  ,[](auto const& /*unused*/, auto& e){ BOOST_CHECK(  ublas::is_valid_v<decltype(e)> ); });
}

BOOST_FIXTURE_TEST_CASE(test_static_extents_comparsion_operator, fixture,
                        *boost::unit_test::label("extents_static") *boost::unit_test::label("equals"))
{
  namespace ublas = boost::numeric::ublas;

  BOOST_CHECK(      e0 == e0      );
  BOOST_CHECK(      e1 == e1      );
  BOOST_CHECK(     e11 == e11     );
  BOOST_CHECK(     e21 == e21     );
  BOOST_CHECK(     e12 == e12     );
  BOOST_CHECK(     e23 == e23     );
  BOOST_CHECK(    e231 == e231    );
  BOOST_CHECK(    e211 == e211    );
  BOOST_CHECK(    e123 == e123    );
  BOOST_CHECK(    e423 == e423    );
  BOOST_CHECK(   e1234 == e1234   );
  BOOST_CHECK(   e4213 == e4213   );
  BOOST_CHECK( e142131 == e142131 );

}

BOOST_AUTO_TEST_SUITE_END()


#include <igl/colon.h>
#include <igl/directed_edge_orientations.h>
#include <igl/directed_edge_parents.h>
#include <igl/forward_kinematics.h>
#include <igl/PI.h>
#include <igl/lbs_matrix.h>
#include <igl/deform_skeleton.h>
#include <igl/dqs.h>
#include <igl/readDMAT.h>
#include <igl/readOFF.h>
#include <igl/arap.h>
#include <igl/opengl/glfw/Viewer.h>

#include <Eigen/Geometry>
#include <Eigen/StdVector>
#include <vector>
#include <algorithm>
#include <iostream>

#include "tutorial_shared_path.h"

typedef
  std::vector<Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> >
  RotationList;

const Eigen::RowVector3d sea_green(70./255.,252./255.,167./255.);
Eigen::MatrixXd V,U;
Eigen::MatrixXi F;
Eigen::VectorXi S,b;
Eigen::RowVector3d mid;
double anim_t = 0.0;
double anim_t_dir = 0.03;
igl::ARAPData arap_data;

bool pre_draw(igl::opengl::glfw::Viewer & viewer)
{
  using namespace Eigen;
  using namespace std;
    MatrixXd bc(b.size(),V.cols());
    for(int i = 0;i<b.size();i++)
    {
      bc.row(i) = V.row(b(i));
      switch(S(b(i)))
      {
        case 0:
        {
          const double r = mid(0)*0.25;
          bc(i,0) += r*sin(0.5*anim_t*2.*igl::PI);
          bc(i,1) -= r+r*cos(igl::PI+0.5*anim_t*2.*igl::PI);
          break;
        }
        case 1:
        {
          const double r = mid(1)*0.15;
          bc(i,1) += r+r*cos(igl::PI+0.15*anim_t*2.*igl::PI);
          bc(i,2) -= r*sin(0.15*anim_t*2.*igl::PI);
          break;
        }
        case 2:
        {
          const double r = mid(1)*0.15;
          bc(i,2) += r+r*cos(igl::PI+0.35*anim_t*2.*igl::PI);
          bc(i,0) += r*sin(0.35*anim_t*2.*igl::PI);
          break;
        }
        default:
          break;
      }
    }
    igl::arap_solve(bc,arap_data,U);
    viewer.data().set_vertices(U);
    viewer.data().compute_normals();
  if(viewer.core().is_animating)
  {
    anim_t += anim_t_dir;
  }
  return false;
}

bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mods)
{
  switch(key)
  {
    case ' ':
      viewer.core().is_animating = !viewer.core().is_animating;
      return true;
  }
  return false;
}

int main(int argc, char *argv[])
{
  using namespace Eigen;
  using namespace std;
  igl::readOFF(TUTORIAL_SHARED_PATH "/decimated-knight.off",V,F);
  U=V;
  igl::readDMAT(TUTORIAL_SHARED_PATH "/decimated-knight-selection.dmat",S);

  // vertices in selection
  igl::colon<int>(0,V.rows()-1,b);
  b.conservativeResize(stable_partition( b.data(), b.data()+b.size(),
   [](int i)->bool{return S(i)>=0;})-b.data());
  // Centroid
  mid = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff());
  // Precomputation
  arap_data.max_iter = 100;
  igl::arap_precomputation(V,F,V.cols(),b,arap_data);

  // Set color based on selection
  MatrixXd C(F.rows(),3);
  RowVector3d purple(80.0/255.0,64.0/255.0,255.0/255.0);
  RowVector3d gold(255.0/255.0,228.0/255.0,58.0/255.0);
  for(int f = 0;f<F.rows();f++)
  {
    if( S(F(f,0))>=0 && S(F(f,1))>=0 && S(F(f,2))>=0)
    {
      C.row(f) = purple;
    }else
    {
      C.row(f) = gold;
    }
  }

  // Plot the mesh with pseudocolors
  igl::opengl::glfw::Viewer viewer;
  viewer.data().set_mesh(U, F);
  viewer.data().set_colors(C);
  viewer.callback_pre_draw = &pre_draw;
  viewer.callback_key_down = &key_down;
  viewer.core().is_animating = false;
  viewer.core().animation_max_fps = 30.;
  cout<<
    "Press [space] to toggle animation"<<endl;
  viewer.launch();
}


//////////////////////////////////////////////////////////////////////////////////
// survival::models::exponential::scalar::detail::lpdf_rt.hpp                   //
//                                                                              //
//  Copyright 2009 Erwann Rogard. Distributed under the Boost                   //
//  Software License, Version 1.0. (See accompanying file                       //
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)            //
//////////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_STATISTICS_DETAIL_DISTRIBUTION_SURVIVAL_MODELS_EXPONENTIAL_SCALAR_DETAIL_LPDF_RT_HPP_ER_2009
#define BOOST_STATISTICS_DETAIL_DISTRIBUTION_SURVIVAL_MODELS_EXPONENTIAL_SCALAR_DETAIL_LPDF_RT_HPP_ER_2009
#include <stdexcept>
#include <string>
#include <cmath>
#include <boost/operators.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/statistics/detail/distribution/survival/response/types/right_truncated/event.hpp>
#include <boost/math/special_functions/fpclassify.hpp>

namespace boost{
namespace statistics{
namespace detail{
namespace distribution{
namespace survival{
namespace exponential_model_{

    template<typename T,typename B>
    T lpdf_rt(
        const T& log_rate,
        const response::event<T,B>& e
    ){

        typedef std::string str_;
        static const str_ msg
            = "exponential<T,right_truncated> : log_unnormalized_pdf";

        typedef T val_;

        val_ result = log_rate;
        result = exp( result );
        result *= (- e.time());
        try{
            if( boost::math::isinf(result) ){
                throw std::runtime_error(" isinf(result)");
            }
            if( boost::math::isnan(result) ){
                throw std::runtime_error(" isnan(result)");
            }
        }catch(std::exception ex){
            str_ str = msg;
            str += ex.what();
            throw std::runtime_error(str);
        }
        if(e.failure()){
            result += log_rate;
        }
        return result;
    }

}// exponential_model_
}// survival
}// distribution
}// detail
}// statistics
}// boost

#endif


#define PY_SSIZE_T_CLEAN
#include "Python.h"
//#include "math.h"
#include "numpy/ndarraytypes.h"
#include "numpy/ufuncobject.h"
#include "numpy/halffloat.h"
#include "approx_class.h"
#include <Eigen/Core>

using Eigen::VectorXd;

/*
 * approx_class.h
 *
 * Each function of the form type_cdf defines the
 * CDF function for a different numpy dtype.
 *
 * Details explaining the Python-C API can be found under
 * 'Extending and Embedding' and 'Python/C API' at
 * docs.python.org .
 *
 */

static PyMethodDef CDFUfuncMethods[] = {
        {NULL, NULL, 0, NULL}
};

/* The loop definitions must precede the PyMODINIT_FUNC. */

static void double_cdf(char **args, npy_intp *dimensions,
                       npy_intp* steps, void* data)
{
    npy_intp i;
    npy_intp j;
    npy_intp n = dimensions[1];  // x size
    npy_intp m = dimensions[2];  // alphas size

    char *x = args[0];  // x
    char *alpha = args[1];
    char *beta = args[2];
    char *alphas = args[3];
    char *out = args[4];
    npy_intp in_step = steps[5], alpha_step = steps[6], out_step = steps[7];

    double loc = *(double *) alpha;
    double scale = *(double *) beta;

    VectorXd param(m);
    for (j = 0; j < m; j++) {
        param[j] = *(double *)alphas;
        alphas += alpha_step;
    }

    Distribution<double> distribution(loc, scale, param);

    double tmp;
#pragma omp parallel for firstprivate(distribution)
    for (i = 0; i < n; i++) {
        /*BEGIN main ufunc computation*/
        tmp = *(double *)(x + i * in_step);
        *(( double *)(out + out_step * i)) = distribution.cdf(tmp);
        /*END main ufunc computation*/
    }
}

/*This gives pointers to the above functions*/
PyUFuncGenericFunction funcs[1] = {reinterpret_cast<PyUFuncGenericFunction>(&double_cdf)};

static char types[5] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE};
static void *data[1] = {NULL};

static struct PyModuleDef moduledef = {
        PyModuleDef_HEAD_INIT,
        "cdf_ufunc",
        NULL,
        -1,
        CDFUfuncMethods,
        NULL,
        NULL,
        NULL,
        NULL
};

PyMODINIT_FUNC PyInit_cdf_ufunc(void)
{
    PyObject *m, *cdf, *d;

    m = PyModule_Create(&moduledef);
    if (!m) {
        return NULL;
    }

    import_array();
    import_umath();

    cdf = PyUFunc_FromFuncAndDataAndSignature(funcs, data, types, 1, 4, 1,
                                              PyUFunc_None, "cdf",
                                              "cdf_docstring", 0, "(n),(),(),(m)->(n)");

    d = PyModule_GetDict(m);

    PyDict_SetItemString(d, "cdf", cdf);
    Py_DECREF(cdf);

    return m;
}


#include "cplex.h"
#include <cassert>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <numeric>

using namespace std;

int ReadSolution(string solfile,
        vector<double> &solution,
        vector<string> &names,
        double &objval);

int main(int argc, char* argv[])
{
    int status = 0;

    CPXENVptr env = CPXopenCPLEX(&status);
    assert(!status);

    cout << "CPLEX version: " <<  CPXversion(env) << endl;

    status = CPXsetintparam(env, CPXPARAM_ScreenOutput, CPX_ON);
    assert(!status);

    CPXLPptr problem = CPXcreateprob(env, &status, "Test problem");
    assert(!status);

    status = CPXreadcopyprob(env,
        problem,
        argv[1],
        NULL);
    assert(!status);

    vector<double> solution;
    vector<string> names;
    double objectivevalue;

    status = ReadSolution(argv[2],
            solution,
            names,
            objectivevalue);
    assert(!status);

    // We sort the solution, according to index in problem
    vector<double> sortedsolution(CPXgetnumcols(env, problem));

    for(int i = 0; i < solution.size(); ++i)
    {
        int idx;
        status = CPXgetcolindex(env,
                problem,
                names[i].c_str(),
                &idx);
        if(&idx != NULL)
        {
            sortedsolution[idx] =solution[i];
            if(idx >= sortedsolution.size())
            {
                cout << "Variable index out of bounds!!" <<  endl;
                exit(1);
            }
        }
        else
        {
            cerr << "Error. Name not found" << endl;
            exit(1);
        }
    }

    vector<int> indices;
    int beg = 0;
    int effortlevel = CPX_MIPSTART_CHECKFEAS;
    for(int i = 0; i < CPXgetnumcols(env, problem); ++i)
        indices.push_back(i);

    status = CPXaddmipstarts(env,
            problem,
            1,
            CPXgetnumcols(env, problem),
            &beg,
            &(indices[0]),
            &(sortedsolution[0]),
            &(effortlevel),
            NULL);
    assert(!status);

    status = CPXsetdblparam(env, CPXPARAM_TimeLimit, 10.0);
    assert(!status);

    status = CPXmipopt(env, problem);

    status = CPXfreeprob(env, &problem);
    assert(!status);

    status = CPXcloseCPLEX(&env);
    assert(!status);

}

int ReadSolution(string solfile,
        vector<double> &solution,
        vector<string> &names,
        double &objval)
{
    int status;

    ifstream infile(solfile.c_str());

    string line;
    vector<string> tokens;

    while(getline(infile, line))
    {
        if(line == "")
            continue;
        boost::algorithm::split(tokens,
                line,
                boost::algorithm::is_space(),
                boost::token_compress_on);
        if(tokens[0] == "=obj=")
        {
            objval = atof(tokens[1].c_str());
        }
        else if(tokens[0] != "#")
        {
            solution.push_back(atof(tokens[1].c_str()));
            names.push_back(tokens[0].c_str());
            //cout << "Variable " << tokens[0] << "= " << atof(tokens[1].c_str()) << endl;
        }
    }

    infile.close();

    return 0;
}


#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/erdos_renyi_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/graphml.hpp>
#include <boost/property_map/dynamic_property_map.hpp>
#include <iostream>
#include <stdlib.h>     /* atoi */
//#include "include_and_types.cpp"

typedef boost::adjacency_list <boost::setS, boost::vecS, boost::directedS, boost::no_property, boost::disallow_parallel_edge_tag> G;
typedef boost::erdos_renyi_iterator<boost::minstd_rand, G> ERGen;

using namespace std;

int main(int argc,char* argv[])
{
    boost::dynamic_properties dp;
    boost::minstd_rand gen;
    // Create graph with 100 nodes and edges with probability 0.05
    float n, p;
    if (argc <= 1){
        n= 20;
        p= 0.05;
    } else if( argc == 3){
        n = atof(argv[1]);
        p = atof(argv[2]);
    } else return 1;

    G g(ERGen(gen, n, p), ERGen(), n);
    boost::write_graphml(cout, g, dp, true);

    return 0;
}


/*
 * This file is part of the Interpolated Polyline (https://github.com/fzi-forschungszentrum-informatik/P3IV),
 * copyright by FZI Forschungszentrum Informatik, licensed under the BSD-3 license (see LICENSE file in main directory)
 */

#pragma once
#include <iostream>
#include <Eigen/Core>

namespace util_probability {

template <typename T, int DistributionDim>
struct NormalDistributionSequence {
    using Mean = Eigen::Matrix<T, Eigen::Dynamic, DistributionDim>;
    using Covariance = Eigen::Matrix<T, Eigen::Dynamic, DistributionDim>;

    NormalDistributionSequence() = default;

    NormalDistributionSequence(const Eigen::Ref<const Mean>& mean_, const Eigen::Ref<const Covariance>& covariance_)
            : _mean{mean_}, _covariance{covariance_} {
    }

    NormalDistributionSequence(const Eigen::Ref<const Mean>& mean_, Eigen::Matrix<T, Eigen::Dynamic, 1>& variance_)
            : _mean{mean_}, _covariance{Covariance::Zero()} {

        for (size_t i = 0; i < variance_.size(); i++) {
            _covariance(i, i) = variance_(i);
        }
    }

    NormalDistributionSequence(std::vector<T> mean_, std::vector<T> covariance_) {
        _mean = Eigen::Map<Mean, Eigen::Unaligned>(mean_.data(), mean_.size() / DistributionDim, DistributionDim);
        _covariance = Eigen::Map<Covariance, Eigen::Unaligned>(
            covariance_.data(), covariance_.size() / DistributionDim, DistributionDim);
    };

    size_t dimension() const {
        return static_cast<size_t>(_mean.size() / DistributionDim);
    }

    void setMean(std::vector<T> mean_) {
        _mean = Eigen::Map<Mean, Eigen::Unaligned>(mean_.data(), mean_.size() / DistributionDim, DistributionDim);
    }

    void setCovariance(std::vector<T> covariance_) {
        _covariance = Eigen::Map<Mean, Eigen::Unaligned>(
            covariance_.data(), covariance_.size() / DistributionDim, DistributionDim);
    }

    Mean mean() const {
        return _mean;
    }

    Covariance covariance() const {
        return _covariance;
    }

    std::vector<T> meanVec() {
        std::vector<T> mean(_mean.data(), _mean.data() + _mean.rows() * _mean.cols());
        return mean;
    }

    T covariance(size_t r, size_t c) const {
        return _covariance(r, c);
    }

protected:
    Mean _mean;
    Covariance _covariance;
};

template <typename T>
struct UnivariateNormalDistributionSequence : NormalDistributionSequence<T, 1> {
    using Mean = Eigen::Matrix<T, Eigen::Dynamic, 1>;
    using Covariance = Eigen::Matrix<T, Eigen::Dynamic, 1>;

    using NormalDistributionSequence<T, 1>::NormalDistributionSequence;

    using NormalDistributionSequence<T, 1>::mean;
    using NormalDistributionSequence<T, 1>::covariance;

    T mean(size_t e) const {
        return this->_mean(e, 0);
    }

    T covariance(size_t e) const {
        return this->_covariance(e, 0);
    }
};

template <typename T>
struct BivariateNormalDistributionSequence : NormalDistributionSequence<T, 2> {
    using Mean = Eigen::Matrix<T, Eigen::Dynamic, 2>;
    using Covariance = Eigen::Matrix<T, Eigen::Dynamic, 4>;

    using NormalDistributionSequence<T, 2>::NormalDistributionSequence;

    BivariateNormalDistributionSequence(const Eigen::Ref<const Mean>& mean_,
                                        Eigen::Matrix<T, Eigen::Dynamic, 1>& variance_)
            : NormalDistributionSequence<T, 2>(mean_, Covariance::Zero()) {

        for (size_t i = 0; i < this->dimension(); i++) {
            this->_covariance(i, 0) = variance_(i);
            this->_covariance(i, 3) = variance_(i);
        }
    }

    using NormalDistributionSequence<T, 2>::mean;
    using NormalDistributionSequence<T, 2>::covariance;

    T mean(size_t e, size_t c) const {
        return this->_mean(e, c);
    }

    T covariance(size_t e, size_t c) const {
        return this->_covariance(e, c);
    }

    virtual Eigen::Matrix<T, Eigen::Dynamic, 2> variance() const {
        Eigen::Matrix<T, Eigen::Dynamic, 2> variance;
        for (size_t i = 0; i < this->dimension(); i++) {
            variance(i, 0) = this->_covariance(i, 0);
            variance(i, 1) = this->_covariance(i, 3);
        }
        return variance;
    }
};

} // namespace util_probability


//
// This file is part of
//
// CTBignum
//
// C++ Library for Compile-Time and Run-Time Multi-Precision and Modular Arithmetic
//
//
// This file is distributed under the Apache License, Version 2.0. See the LICENSE
// file for details.

#include <NTL/ZZ.h>
#include <NTL/ZZ_p.h>
#include <benchmark/benchmark.h>
#include <random>

#include <ctbignum/ctbignum.hpp>
#include <ctbignum/bigint.hpp>
#include <ctbignum/mult.hpp>
#include <ctbignum/mod_exp.hpp>
#include <gmp.h>

template <size_t Len>
static void mul_gmp(benchmark::State &state) {

  using namespace cbn;

  size_t total_sz = 2 * Len  * 1000;

  std::vector<uint64_t> data(total_sz);
  std::default_random_engine generator;
  std::uniform_int_distribution<uint64_t> distribution(0);
  for (auto& limb : data)
    limb = distribution(generator);

  size_t i = 0;
  auto base_ptr = reinterpret_cast<mp_limb_t*>(data.data());

  mp_limb_t result[2*Len];

  for (auto _ : state) {

    mpn_mul(result, base_ptr + i, Len, base_ptr + i + Len, Len);
    benchmark::DoNotOptimize(result);

    i += 2 * Len;
    if (i == total_sz)
     i = 0;
  }
}

template <size_t Len>
static void mul_cbn(benchmark::State &state) {

  using namespace cbn;

  size_t total_sz = 2* Len  * 1000;

  std::vector<uint64_t> data(total_sz);
  std::default_random_engine generator;
  std::uniform_int_distribution<uint64_t> distribution(0);
  for (auto& limb : data)
    limb = distribution(generator);

  size_t i = 0;
  auto base_ptr = data.data();

  for (auto _ : state) {

    auto x = reinterpret_cast<big_int<Len>*>(base_ptr + i);
    auto y = reinterpret_cast<big_int<Len>*>(base_ptr + i + Len);
    auto j = cbn::mul(*x, *y);
    benchmark::DoNotOptimize(j);

    i += 2 * Len;
    if (i == total_sz)
     i = 0;
  }
}

/*
template <size_t Len>
static void mul_cbn(benchmark::State &state) {

  using namespace cbn;
  std::default_random_engine generator;
  std::uniform_int_distribution<uint64_t> distribution(0);

  big_int<Len> x;
  big_int<Len> y;
  for (int i = 0; i < Len; ++i) {
    x[i] = distribution(generator);
    y[i] = distribution(generator);
  }

  for (auto _ : state) {
    auto k = cbn::mul(x, y);
    benchmark::DoNotOptimize(k);
  }
}
*/

template <size_t Len>
static void mul_ntl(benchmark::State &state) {

  using NTL::ZZ;
  using NTL::ZZ_p;
  using NTL::conv;

  auto x = NTL::RandomBits_ZZ(Len*64);
  auto y = NTL::RandomBits_ZZ(Len*64);
  ZZ z;

  for (auto _ : state) {
    mul(z, x, y);
    benchmark::DoNotOptimize(z);
  }
}

BENCHMARK_TEMPLATE(mul_cbn, 2);
BENCHMARK_TEMPLATE(mul_ntl, 2);
BENCHMARK_TEMPLATE(mul_gmp, 2);

BENCHMARK_TEMPLATE(mul_cbn, 3);
BENCHMARK_TEMPLATE(mul_ntl, 3);
BENCHMARK_TEMPLATE(mul_gmp, 3);

BENCHMARK_TEMPLATE(mul_cbn, 4);
BENCHMARK_TEMPLATE(mul_ntl, 4);
BENCHMARK_TEMPLATE(mul_gmp, 4);

BENCHMARK_TEMPLATE(mul_cbn, 5);
BENCHMARK_TEMPLATE(mul_ntl, 5);
BENCHMARK_TEMPLATE(mul_gmp, 5);

BENCHMARK_TEMPLATE(mul_cbn, 6);
BENCHMARK_TEMPLATE(mul_ntl, 6);
BENCHMARK_TEMPLATE(mul_gmp, 6);

BENCHMARK_TEMPLATE(mul_cbn, 7);
BENCHMARK_TEMPLATE(mul_ntl, 7);
BENCHMARK_TEMPLATE(mul_gmp, 7);

BENCHMARK_TEMPLATE(mul_cbn, 8);
BENCHMARK_TEMPLATE(mul_ntl, 8);
BENCHMARK_TEMPLATE(mul_gmp, 8);

BENCHMARK_MAIN();


#ifndef STAN_MATH_PRIM_SCAL_PROB_EXPONENTIAL_RNG_HPP
#define STAN_MATH_PRIM_SCAL_PROB_EXPONENTIAL_RNG_HPP

#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_nonnegative.hpp>
#include <stan/math/prim/scal/err/check_not_nan.hpp>
#include <stan/math/prim/scal/err/check_positive_finite.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/meta/length.hpp>
#include <stan/math/prim/scal/meta/VectorBuilder.hpp>
#include <stan/math/prim/scal/meta/return_type.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>
#include <boost/random/exponential_distribution.hpp>
#include <boost/random/variate_generator.hpp>

namespace stan {
  namespace math {

    template <class RNG>
    inline double
    exponential_rng(double beta,
                    RNG& rng) {
      using boost::variate_generator;
      using boost::exponential_distribution;

      static const char* function("exponential_rng");

      check_positive_finite(function, "Inverse scale parameter", beta);

      variate_generator<RNG&, exponential_distribution<> >
        exp_rng(rng, exponential_distribution<>(beta));
      return exp_rng();
    }

  }
}
#endif


#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE COMPUTE

#include <boost/test/unit_test.hpp>

#include "api/umo.hpp"

#include <cmath>
#include <vector>
#include <algorithm>

using namespace umo;

BOOST_AUTO_TEST_CASE(FloatCompute) {
    Model model;
    FloatExpression dec1 = model.floatVar(0.0, 10.0);
    FloatExpression dec2 = model.floatVar(0.0, 10.0);
    FloatExpression x01 = dec1 + dec2;
    FloatExpression x02 = dec1 - dec2;
    FloatExpression x03 = dec1 * dec2;
    FloatExpression x04 = dec1 / dec2;
    FloatExpression x05 = -dec1;
    for (double val1 : {5.0, -4.0, 2.5}) {
        for (double val2 : {-7.0, 2.0, 1.3}) {
            dec1.setValue(val1);
            dec2.setValue(val2);
            BOOST_CHECK_EQUAL(x01.getValue(), val1 + val2);
            BOOST_CHECK_EQUAL(x02.getValue(), val1 - val2);
            BOOST_CHECK_EQUAL(x03.getValue(), val1 * val2);
            BOOST_CHECK_EQUAL(x04.getValue(), val1 / val2);
            BOOST_CHECK_EQUAL(x05.getValue(), -val1);
        }
    }
    model.check();
}

BOOST_AUTO_TEST_CASE(IntCompute) {
    Model model;
    IntExpression dec1 = model.intVar(0, 10);
    IntExpression dec2 = model.intVar(0, 10);
    IntExpression x01 = dec1 + dec2;
    IntExpression x02 = dec1 - dec2;
    IntExpression x03 = dec1 * dec2;
    IntExpression x04 = dec1 / dec2;
    IntExpression x05 = dec1 % dec2;
    IntExpression x06 = -dec1;
    for (long long val1 : {5, -4, 0}) {
        for (long long val2 : {-7, 2}) {
            dec1.setValue(val1);
            dec2.setValue(val2);
            BOOST_CHECK_EQUAL(x01.getValue(), val1 + val2);
            BOOST_CHECK_EQUAL(x02.getValue(), val1 - val2);
            BOOST_CHECK_EQUAL(x03.getValue(), val1 * val2);
            BOOST_CHECK_EQUAL(x04.getValue(), val1 / val2);
            BOOST_CHECK_EQUAL(x05.getValue(), val1 % val2);
            BOOST_CHECK_EQUAL(x06.getValue(), -val1);
        }
    }
    model.check();
}

BOOST_AUTO_TEST_CASE(BoolCompute) {
    Model model;
    BoolExpression dec1 = model.boolVar();
    BoolExpression dec2 = model.boolVar();
    BoolExpression x01 = dec1 && dec2;
    BoolExpression x02 = dec1 || dec2;
    BoolExpression x03 = dec1 && !dec2;
    BoolExpression x04 = !dec1 || dec2;
    BoolExpression x05 = !(dec1 || dec2);
    BoolExpression x06 = !(dec1 && dec2);
    BoolExpression x07 = !dec1;
    for (bool val1 : {false, true}) {
        for (bool val2 : {false, true}) {
            dec1.setValue(val1);
            dec2.setValue(val2);
            BOOST_CHECK_EQUAL(x01.getValue(), val1 && val2);
            BOOST_CHECK_EQUAL(x02.getValue(), val1 || val2);
            BOOST_CHECK_EQUAL(x03.getValue(), val1 && !val2);
            BOOST_CHECK_EQUAL(x04.getValue(), !val1 || val2);
            BOOST_CHECK_EQUAL(x05.getValue(), !(val1 || val2));
            BOOST_CHECK_EQUAL(x06.getValue(), !(val1 && val2));
            BOOST_CHECK_EQUAL(x07.getValue(), !val1);
        }
    }
    model.check();
}

BOOST_AUTO_TEST_CASE(Operations) {
    Model model;
    FloatExpression dec = model.floatVar(-10.0, 10.0);
    FloatExpression x01 = umo::exp(dec);
    FloatExpression x02 = umo::cos(dec);
    FloatExpression x03 = umo::atan(dec);
    for (double val : {5.0, -4.0, 2.5}) {
        dec.setValue(val);
        BOOST_CHECK_EQUAL(x01.getValue(), std::exp(val));
        BOOST_CHECK_EQUAL(x02.getValue(), std::cos(val));
        BOOST_CHECK_EQUAL(x03.getValue(), std::atan(val));
    }
    model.check();
}

BOOST_AUTO_TEST_CASE(Comparisons) {
    Model model;
    FloatExpression dec1 = model.floatVar(0.0, 10.0);
    FloatExpression dec2 = model.floatVar(0.0, 10.0);
    BoolExpression x01 = dec1 == dec2;
    BoolExpression x02 = dec1 != dec2;
    BoolExpression x03 = dec1 <= dec2;
    BoolExpression x04 = dec1 >= dec2;
    BoolExpression x05 = dec1 < dec2;
    BoolExpression x06 = dec1 > dec2;

    // Should compare equal
    dec1.setValue(1.0 - 1e-7);
    dec2.setValue(1.0);
    BOOST_CHECK_EQUAL(x01.getValue(), true);  // ==
    BOOST_CHECK_EQUAL(x02.getValue(), false); // !=
    BOOST_CHECK_EQUAL(x03.getValue(), true);  // <=
    BOOST_CHECK_EQUAL(x04.getValue(), true);  // >=
    BOOST_CHECK_EQUAL(x05.getValue(), false); // <
    BOOST_CHECK_EQUAL(x06.getValue(), false); // >

    // Should compare different
    dec1.setValue(1.0 - 1e-5);
    dec2.setValue(1.0);
    BOOST_CHECK_EQUAL(x01.getValue(), false); // ==
    BOOST_CHECK_EQUAL(x02.getValue(), true);  // !=
    BOOST_CHECK_EQUAL(x03.getValue(), true);  // <=
    BOOST_CHECK_EQUAL(x04.getValue(), false); // >=
    BOOST_CHECK_EQUAL(x05.getValue(), true);  // <
    BOOST_CHECK_EQUAL(x06.getValue(), false); // >

    // Should compare equal
    dec1.setValue(1e-9);
    dec2.setValue(0.0);
    BOOST_CHECK_EQUAL(x01.getValue(), true);  // ==
    BOOST_CHECK_EQUAL(x02.getValue(), false); // !=
    BOOST_CHECK_EQUAL(x03.getValue(), true);  // <=
    BOOST_CHECK_EQUAL(x04.getValue(), true);  // >=
    BOOST_CHECK_EQUAL(x05.getValue(), false); // <
    BOOST_CHECK_EQUAL(x06.getValue(), false); // >

    // Should compare different
    dec1.setValue(1e-7);
    dec2.setValue(0.0);
    BOOST_CHECK_EQUAL(x01.getValue(), false); // ==
    BOOST_CHECK_EQUAL(x02.getValue(), true);  // !=
    BOOST_CHECK_EQUAL(x03.getValue(), false); // <=
    BOOST_CHECK_EQUAL(x04.getValue(), true);  // >=
    BOOST_CHECK_EQUAL(x05.getValue(), false); // <
    BOOST_CHECK_EQUAL(x06.getValue(), true);  // >

    // Should compare different
    dec1.setValue(1e-5);
    dec2.setValue(0.0);
    BOOST_CHECK_EQUAL(x01.getValue(), false); // ==
    BOOST_CHECK_EQUAL(x02.getValue(), true);  // !=
    BOOST_CHECK_EQUAL(x03.getValue(), false); // <=
    BOOST_CHECK_EQUAL(x04.getValue(), true);  // >=
    BOOST_CHECK_EQUAL(x05.getValue(), false); // <
    BOOST_CHECK_EQUAL(x06.getValue(), true);  // >

    // Just for directions
    dec1.setValue(1.0);
    dec2.setValue(2.0);
    BOOST_CHECK_EQUAL(x03.getValue(), true);  // <=
    BOOST_CHECK_EQUAL(x04.getValue(), false); // >=
    BOOST_CHECK_EQUAL(x05.getValue(), true);  // <
    BOOST_CHECK_EQUAL(x06.getValue(), false); // >
    dec1.setValue(2.0);
    dec2.setValue(1.0);
    BOOST_CHECK_EQUAL(x03.getValue(), false); // <=
    BOOST_CHECK_EQUAL(x04.getValue(), true);  // >=
    BOOST_CHECK_EQUAL(x05.getValue(), false); // <
    BOOST_CHECK_EQUAL(x06.getValue(), true);  // >

    model.check();
}

BOOST_AUTO_TEST_CASE(ModelStatus) {
    Model model;
    BoolExpression dec = model.boolVar();
    constraint(dec);
    dec.setValue(false);
    BOOST_CHECK(model.getStatus() == Status::Invalid);
    dec.setValue(true);
    BOOST_CHECK(model.getStatus() == Status::Valid);
}

BOOST_AUTO_TEST_CASE(IntNary) {
    Model model;
    IntExpression dec1 = model.intVar();
    IntExpression dec2 = model.intVar();
    IntExpression dec3 = model.intVar();
    std::vector<IntExpression> vec{dec1, dec2, dec3};
    IntExpression x01 = sum(vec);
    IntExpression x02 = prod(vec);
    IntExpression x03 = min(vec);
    IntExpression x04 = max(vec);
    for (long long val1 : {5, -4, 0}) {
        for (long long val2 : {-7, 2, 8}) {
            for (long long val3 : {-17, -5, 0, 4}) {
                dec1.setValue(val1);
                dec2.setValue(val2);
                dec3.setValue(val3);
                std::vector<long long> vals{val1, val2, val3};
                BOOST_CHECK_EQUAL(x01.getValue(), val1 + val2 + val3);
                BOOST_CHECK_EQUAL(x02.getValue(), val1 * val2 * val3);
                BOOST_CHECK_EQUAL(x03.getValue(), *std::min_element(vals.begin(), vals.end()));
                BOOST_CHECK_EQUAL(x04.getValue(), *std::max_element(vals.begin(), vals.end()));
            }
        }
    }
    model.check();
}

BOOST_AUTO_TEST_CASE(BoolNary) {
    Model model;
    BoolExpression dec1 = model.boolVar();
    BoolExpression dec2 = model.boolVar();
    BoolExpression dec3 = model.boolVar();
    std::vector<BoolExpression> vec{dec1, dec2, dec3};
    BoolExpression x01 = logical_or(vec);
    BoolExpression x02 = logical_and(vec);
    BoolExpression x03 = logical_xor(vec);
    for (long long val1 : {false, true}) {
        for (long long val2 : {false, true}) {
            for (long long val3 : {false, true}) {
                dec1.setValue(val1);
                dec2.setValue(val2);
                dec3.setValue(val3);
                BOOST_CHECK_EQUAL(x01.getValue(), val1 || val2 || val3);
                BOOST_CHECK_EQUAL(x02.getValue(), val1 && val2 && val3);
                BOOST_CHECK_EQUAL(x03.getValue(), val1 ^ val2 ^ val3);
            }
        }
    }
    model.check();
}


#include <boost/math/distributions/poisson.hpp>
#include <iostream>

// C++17 allows us to omit tail template parameters.
template<template<class>class T, typename... U>
auto f(double q, U&&... params) {
    T<double> dist(params...);
    return boost::math::quantile(dist, q);
}

// C++14 requires all explicit template parameters.
template<template<class,class>class T, typename... U>
auto g(double q, U&&... params) {
    T<double, boost::math::policies::policy<>> dist(params...);
    return boost::math::quantile(dist, q);
}

void compilationError(void) {
//  This may cause error message which is hard to understand.
//  int policy = 0;
    using namespace boost::math::policies;
//  This "policy" is namespace boost::math::policies::policy, not a local variable.
    boost::math::poisson_distribution<double, policy<discrete_quantile<integer_round_up>>> dist;
}

int main(int argc, char* argv[]) {
    using namespace boost::math;
    std::cout << f<boost::math::poisson_distribution>(0.9, 2.5) << "\n";
    std::cout << g<boost::math::poisson_distribution>(0.9, 2.5) << "\n";
    return 0;
}

/*
Local Variables:
mode: c++
coding: utf-8-dos
tab-width: nil
c-file-style: "stroustrup"
End:
*/


// Copyright (c) 2021 Stig Rune Sellevag
//
// This file is distributed under the MIT License. See the accompanying file
// LICENSE.txt or http://www.opensource.org/licenses/mit-license.php for terms
// and conditions.

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4305)
#pragma warning(disable : 5054)
#endif

#include <scilib/mdarray.h>
#include <scilib/linalg.h>
#include <chrono>
#include <iostream>
#include <Eigen/Dense>

using Timer = std::chrono::duration<double, std::milli>;

void print(int n, const Timer& t_eigen, const Timer& t_sci)
{
    std::cout << "Eigenvalues for symmetric matrix:\n"
              << "---------------------------------\n"
              << "size =      " << n << " x " << n << '\n'
              << "sci/eigen = " << t_sci.count() / t_eigen.count() << "\n\n";
}

void benchmark(int n)
{
    using namespace Sci;
    using namespace Sci::Linalg;

    Eigen::MatrixXd a1 = Eigen::MatrixXd::Random(n, n);
    Eigen::MatrixXd a2 = a1 + a1.transpose();
    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es;
    auto t1 = std::chrono::high_resolution_clock::now();
    es.compute(a2);
    auto t2 = std::chrono::high_resolution_clock::now();
    Timer t_eigen = t2 - t1;

    Matrix<double> b1 = randu<Matrix<double>>(n, n);
    Matrix<double> b1_t = b1;
    Matrix<double> b2(n, n);
    matrix_product(transposed(b1_t.view()), b1.view(), b2.view());
    Vector<double> wr(n);
    t1 = std::chrono::high_resolution_clock::now();
    eigs(b2.view(), wr.view());
    t2 = std::chrono::high_resolution_clock::now();
    Timer t_sci = t2 - t1;

    print(n, t_eigen, t_sci);
}

int main()
{
    int n = 10;
    benchmark(n);

    n = 100;
    benchmark(n);

    n = 500;
    benchmark(n);
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif


#include <boost/test/minimal.hpp>
#include <ctime>

#include "./suffix_array.hpp"
#include "./utils.hpp"

using namespace std;

// SuffixArray O(nlogn^2)
#define REP(i,n) for(int i=0; i<(int)(n) ; i++)
struct SAComp{
	int h;
	const vector<int> &g;
	SAComp(int h, vector<int> &g):h(h),g(g){}
	bool operator()(int a,int b){
		return a == b ? false : g[a] != g[b] ? g[a] < g[b] : g[a + h] < g[b + h];
	}
};

vector<int> SuffixArray(const string &str){
	int n = str.size();
	vector<int> sa(n+1),g(n+1),b(n+1);
	REP(i,n+1)sa[i] = i,g[i] = str[i];
	b[0] = b[n] = 0;
	SAComp comp(0,g);
	sort(sa.begin(),sa.end(),comp);
	for(comp.h = 1; b[n] != n; comp.h *= 2) {
		sort(sa.begin(),sa.end(),comp);
		REP(i,n)b[i+1] = b[i] + comp(sa[i], sa[i+1]);
		REP(i,n+1)g[sa[i]] = b[i];
	}
	return sa;
}
// HeightArray O(n)
vector<int> HeightArray(const string &str, const vector<int> &sa){
	int n = str.size(),h = 0;
	vector<int> ha(n+1),b(n+1);
	REP(i,n+1)b[sa[i]] = i;
	REP(i,n+1){
		if (b[i]){
			for (int j=sa[b[i]-1]; j+h<n && i+h<n && str[j+h]==str[i+h]; ++h);
			ha[b[i]] = h;
		}else ha[b[i]] = -1;
		if(h>0)--h;
	}
	return ha;
}

vector<int> create_vector(int arr[], int len){
    return vector<int>(arr, arr+len);
}

void test_create_suffix_array_from_string(){
    string data[] = {"mmiissiissippi", "abracadabra"};
    vector<int> expected[] = {
          create_vector((int[]){14,13,2,6,10,3,7,1,0,12,11,5,9,4,8}, 15)
        , create_vector((int[]){11,10,7,0,3,5,8,1,4,6,9,2}, 12)
    };
    for(int i=0 ; i<2 ; i++){
        vector<int> actual = sasa::create_suffix_array_from_string(data[i]);
        BOOST_CHECK(actual.size() == expected[i].size());
        for(int j=0 ; j<(int)actual.size() ; j++){
            BOOST_CHECK(actual[j] == expected[i][j]);
        }
    }
}

void test_construction_speed(){
    int n = 5000000;
    string str = "";
    for(int i=0 ; i<n ; i++){
        str += rand() % 2 ? 'a' : 'b';
    }
    clock_t start,end;
    start = clock();
    sasa::create_suffix_array_from_string(str);
    end = clock();

    double sais_time = (double)(end - start)/CLOCKS_PER_SEC;

    start = clock();
    SuffixArray(str);
    end = clock();

    double ls_time = (double)(end - start)/CLOCKS_PER_SEC;

    cout << "sais time: " << sais_time << " [s]" << endl;
    cout << "ls time: " << ls_time << " [s]" << endl;
}

int test_main(int argc, char* argv[]){
    test_create_suffix_array_from_string();
    test_construction_speed();
    return 0;
}


#include <boost/integer/common_factor_rt.hpp>


#include <boost/timer/timer.hpp>
#include <Eigen/Core>
#include <iostream>
#include <memory>

#include <bayesclassifier.h>
#include <knnclassifier.h>
#include <naivebayesclassifier.h>

#include "tsv.h"

using Eigen::MatrixXd;
using std::cout;
using std::make_unique;
using std::string;
using std::vector;

void print(const Eigen::VectorXd& v) {
    for (int i = 0; i < v.size(); ++i) {
        if (i)
            cout << ", ";
        cout << v(i);
    }
}

int main(int argc, char * argv[]) {
    // parse arguments
    if (argc != 3) {
        cout << "Usage: " << argv[0] << " file algorithm\n"
             << "Algorithm can be b, k or n:\n"
             << "    b -- Full Bayes classifier\n"
             << "    n -- Naive Bayes classifier\n"
             << "    k -- K Nearest Neighbors classifier with k=5\n";
        return 1;
    }
    string filename = argv[1];
    char algorithm = argv[2][0];

    // load input data
    ClassificationDataset tr = load_tsv(filename);
    ClassificationDataset te;
    unsigned n = tr.x.size();

    // split into training and test data
    unsigned n_tr = (unsigned)std::round(0.7 * (double)n);
    unsigned n_te = n - n_tr;
    te.x.insert(te.x.cbegin(), tr.x.cbegin() + n_tr, tr.x.cend());
    te.y.insert(te.y.cbegin(), tr.y.cbegin() + n_tr, tr.y.cend());
    tr.x.erase(tr.x.cbegin() + n_tr, tr.x.cend());
    tr.y.erase(tr.y.cbegin() + n_tr, tr.y.cend());
    cout << n << " instances (" << n_tr << " training, " << n_te << " test)\n";

    // train classifier
    std::unique_ptr<Classifier> c;
    if (algorithm == 'b') {
        cout << "Training Bayes classifier...\n";
        boost::timer::auto_cpu_timer t;
        c = make_unique<BayesClassifier>(tr.x, tr.y);
    } else if (algorithm == 'k') {
        cout << "Training K Nearest Neighbors classifier...\n";
        boost::timer::auto_cpu_timer t;
        c = make_unique<KnnClassifier>(std::move(tr.x), std::move(tr.y), 5);
    } else {
        cout << "Training Naive Bayes classifier...\n";
        boost::timer::auto_cpu_timer t;
        c = make_unique<NaiveBayesClassifier>(tr.x, tr.y);
    }

    // apply classifier to test data
    Eigen::MatrixXd m = Eigen::MatrixXd::Zero(2,2);
    {
        cout << "Predicting class labels...\n";
        boost::timer::auto_cpu_timer t;
        auto xi = te.x.cbegin();
        auto yi = te.y.cbegin();
        for (; xi != te.x.cend(); ++xi, ++yi)
            ++m(c->predict(*xi), *yi);
    }

    double true_positive  = m(1,1);
    double false_positive = m(1,0);
    double true_negative  = m(0,0);
    double false_negative = m(0,1);

    double accuracy  = (true_positive + true_negative) /  (double)n_te;
    double precision = true_positive / (true_positive + false_positive);
    double recall    = true_positive / (true_positive + false_negative);

    cout << "Results:\n"
         << "    True positives:  " << true_positive << "\n"
         << "    False positives: " << false_positive << "\n"
         << "    True negatives:  " << true_negative << "\n"
         << "    False negatives: " << false_negative << "\n"
         << "    Accuracy:        " << accuracy << "\n"
         << "    Precision:       " << precision << "\n"
         << "    Recall:          " << recall << "\n";

    return 0;
}


#include "benchmark.h"

#include <Eigen/Core>
#include <Eigen/Sparse>
#include <chrono>
#include <iostream>
#include <cstdlib>
#include <assert.h>

void benchmark_Eigen(
    const std::vector<std::string>& parameterNames,
    const Json::Array& parameters,
    const std::vector<std::string>& returnNames,
    Json::Array& returnValues)
{
    //number of runs for time measures
    const int runs = 10;
	const int subruns = 2;

    int numConfigs = parameters.Size();
    for (int config = 0; config < numConfigs; ++config)
    {
        //Input
        int gridSize = parameters[config][0].AsInt32();
        double totalTime = 0;
        std::cout << "  Grid Size: " << gridSize << std::flush;
		int matrixSize = gridSize * gridSize;

		//Create matrix
#define IDX(x, y) ((y) + (x)*gridSize)
		Eigen::SparseMatrix<float, Eigen::RowMajor> matrix(matrixSize, matrixSize);
		matrix.reserve(Eigen::VectorXi::Constant(matrixSize, 5));
		for (int x=0; x<gridSize; ++x) for (int y=0; y<gridSize; ++y)
		{
			int row = IDX(x, y);
			if (x > 0) matrix.insert(row, IDX(x - 1, y)) = -1;
			if (y > 0) matrix.insert(row, IDX(x, y - 1)) = -1;
			matrix.insert(row, row) = 4;
			if (y < gridSize - 1) matrix.insert(row, IDX(x, y + 1)) = -1;
			if (x < gridSize - 1) matrix.insert(row, IDX(x + 1, y)) = -1;
		}
		matrix.makeCompressed();

		//Create vector
		Eigen::VectorXf x = Eigen::VectorXf::Random(matrixSize);
		Eigen::VectorXf r(matrixSize);

        //Run it multiple times
        for (int run = 0; run < runs; ++run)
        {
            //Main logic
            auto start = std::chrono::steady_clock::now();

            //csrmv
			for (int i = 0; i < subruns; ++i) {
				r.noalias() = matrix * x;
			}

            auto finish = std::chrono::steady_clock::now();
            double elapsed = std::chrono::duration_cast<
                std::chrono::duration<double> >(finish - start).count() * 1000 / subruns;
            totalTime += elapsed;
        }

        //Result
        Json::Array result;
        double finalTime = totalTime / runs;
        result.PushBack(finalTime);
        returnValues.PushBack(result);
        std::cout << " -> " << finalTime << "ms" << std::endl;
    }
}


#pragma once

#include <Eigen/Dense>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>

#include <string>

using namespace Eigen;
using namespace std;

bool updateCosy(const boost::shared_ptr<pcl::visualization::PCLVisualizer>& viewer
    ,const Matrix3f& R, string prefix="cosy", float scale=1.0f);

void addCosy(const boost::shared_ptr<pcl::visualization::PCLVisualizer>& viewer,
    const Matrix3f& R, string prefix="cosy", float scale=1.0f, int viewport=0);


//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>

/*

  This example demonstrates the usage of the connected_components
  algorithm on a undirected graph. The example graphs come from
  "Introduction to Algorithms", Cormen, Leiserson, and Rivest p. 87
  (though we number the vertices from zero instead of one).

  Sample output:

  Total number of components: 3
  Vertex 0 is in component 0
  Vertex 1 is in component 0
  Vertex 2 is in component 1
  Vertex 3 is in component 2
  Vertex 4 is in component 0
  Vertex 5 is in component 1

 */

using namespace std;

int main(int , char* [])
{
  using namespace boost;
  {
    typedef adjacency_list <vecS, vecS, undirectedS> Graph;

    Graph G;
    add_edge(0, 1, G);
    add_edge(1, 4, G);
    add_edge(4, 0, G);
    add_edge(2, 5, G);

    std::vector<int> component(num_vertices(G));
    int num = connected_components(G, &component[0]);

    std::vector<int>::size_type i;
    cout << "Total number of components: " << num << endl;
    for (i = 0; i != component.size(); ++i)
      cout << "Vertex " << i <<" is in component " << component[i] << endl;
    cout << endl;
  }
  return 0;
}


// Copyright Louis Dionne 2013-2016
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/and.hpp>
#include <boost/hana/assert.hpp>
#include <boost/hana/comparing.hpp>
#include <boost/hana/div.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/eval_if.hpp>
#include <boost/hana/greater.hpp>
#include <boost/hana/greater_equal.hpp>
#include <boost/hana/if.hpp>
#include <boost/hana/less.hpp>
#include <boost/hana/less_equal.hpp>
#include <boost/hana/max.hpp>
#include <boost/hana/min.hpp>
#include <boost/hana/minus.hpp>
#include <boost/hana/mod.hpp>
#include <boost/hana/mult.hpp>
#include <boost/hana/negate.hpp>
#include <boost/hana/not.hpp>
#include <boost/hana/not_equal.hpp>
#include <boost/hana/one.hpp>
#include <boost/hana/or.hpp>
#include <boost/hana/ordering.hpp>
#include <boost/hana/plus.hpp>
#include <boost/hana/power.hpp>
#include <boost/hana/tuple.hpp>
#include <boost/hana/while.hpp>
#include <boost/hana/zero.hpp>

#include <laws/base.hpp>
#include <laws/comparable.hpp>
#include <laws/euclidean_ring.hpp>
#include <laws/group.hpp>
#include <laws/logical.hpp>
#include <laws/monoid.hpp>
#include <laws/orderable.hpp>
#include <support/cnumeric.hpp>
#include <support/numeric.hpp>

#include <cstdlib>
#include <vector>
namespace hana = boost::hana;

struct invalid {
    template <typename T>
    operator T const() { std::abort(); }
};

int main() {
    //////////////////////////////////////////////////////////////////////////
    // Comparable
    //////////////////////////////////////////////////////////////////////////
    {
        hana::test::_injection<0> f{};
        auto x = numeric(1);
        auto y = numeric(2);

        // equal
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(x, x));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::equal(x, y)));
        }

        // not_equal
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_equal(x, y));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::not_equal(x, x)));
        }

        // comparing
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::comparing(f)(x, x),
                hana::equal(f(x), f(x))
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::comparing(f)(x, y),
                hana::equal(f(x), f(y))
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Orderable
    //////////////////////////////////////////////////////////////////////////
    {
        auto ord = numeric;

        // _injection is also monotonic
        hana::test::_injection<0> f{};

        // less
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::less(ord(0), ord(1)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::less(ord(0), ord(0))));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::less(ord(1), ord(0))));
        }

        // less_equal
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::less_equal(ord(0), ord(1)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::less_equal(ord(0), ord(0)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::less_equal(ord(1), ord(0))));
        }

        // greater_equal
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::greater_equal(ord(1), ord(0)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::greater_equal(ord(0), ord(0)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::greater_equal(ord(0), ord(1))));
        }

        // greater
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::greater(ord(1), ord(0)));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::greater(ord(0), ord(0))));
            BOOST_HANA_CONSTEXPR_CHECK(hana::not_(hana::greater(ord(0), ord(1))));
        }

        // max
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::max(ord(0), ord(0)), ord(0)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::max(ord(1), ord(0)), ord(1)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::max(ord(0), ord(1)), ord(1)
            ));
        }

        // min
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::min(ord(0), ord(0)),
                ord(0)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::min(ord(1), ord(0)),
                ord(0)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::min(ord(0), ord(1)),
                ord(0)
            ));
        }

        // ordering
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::ordering(f)(ord(1), ord(0)),
                hana::less(f(ord(1)), f(ord(0)))
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::ordering(f)(ord(0), ord(1)),
                hana::less(f(ord(0)), f(ord(1)))
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::ordering(f)(ord(0), ord(0)),
                hana::less(f(ord(0)), f(ord(0)))
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Monoid
    //////////////////////////////////////////////////////////////////////////
    {
        constexpr int x = 2, y = 3;

        // zero
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::zero<Numeric>(), numeric(0)
            ));
        }

        // plus
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::plus(numeric(x), numeric(y)),
                numeric(x + y)
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Group
    //////////////////////////////////////////////////////////////////////////
    {
        constexpr int x = 2, y = 3;

        // minus
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::minus(numeric(x), numeric(y)),
                numeric(x - y)
            ));
        }

        // negate
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::negate(numeric(x)),
                numeric(-x)
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Ring
    //////////////////////////////////////////////////////////////////////////
    {
        constexpr int x = 2, y = 3;

        // one
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::one<Numeric>(),
                numeric(1)
            ));
        }

        // mult
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::mult(numeric(x), numeric(y)),
                numeric(x * y)
            ));
        }

        // power
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::power(numeric(x), hana::zero<CNumeric<int>>()),
                hana::one<Numeric>()
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::power(numeric(x), hana::one<CNumeric<int>>()),
                numeric(x)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::power(numeric(x), cnumeric<int, 2>),
                hana::mult(numeric(x), numeric(x))
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::power(numeric(x), cnumeric<int, 3>),
                hana::mult(hana::mult(numeric(x), numeric(x)), numeric(x))
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // EuclideanRing
    //////////////////////////////////////////////////////////////////////////
    {
        constexpr int x = 6, y = 3, z = 4;

        // div
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::div(numeric(x), numeric(y)),
                numeric(x / y)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::div(numeric(x), numeric(z)),
                 numeric(x/ z)
            ));
        }

        // mod
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::mod(numeric(x), numeric(y)),
                numeric(x % y)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::mod(numeric(x), numeric(z)),
                numeric(x % z)
            ));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Logical
    //////////////////////////////////////////////////////////////////////////
    {
        auto logical = numeric;
        auto comparable = numeric;

        // not_
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::not_(logical(true)),
                logical(false)
            ));
        }

        // and_
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(false)),
                logical(false)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true), logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true), logical(false)),
                logical(false)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(false), invalid{}),
                logical(false)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true), logical(true), logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true), logical(true), logical(false)),
                logical(false)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(true), logical(false), invalid{}),
                logical(false)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::and_(logical(false), invalid{}, invalid{}),
                logical(false)
            ));
        }

        // or_
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false)),
                logical(false)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false), logical(false)),
                logical(false)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false), logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(true), invalid{}),
                logical(true)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false), logical(false), logical(false)),
                logical(false)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false), logical(false), logical(true)),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(false), logical(true), invalid{}),
                logical(true)
            ));
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::or_(logical(true), invalid{}, invalid{}),
                logical(true)
            ));
        }

        // if_
        {
            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::if_(logical(true), comparable(0), comparable(1)),
                comparable(0)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::if_(logical(false), comparable(0), comparable(1)),
                comparable(1)
            ));
        }

        // eval_if
        {
            auto t = [=](auto) { return comparable(0); };
            auto e = [=](auto) { return comparable(1); };

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::eval_if(logical(true), t, e),
                comparable(0)
            ));

            BOOST_HANA_CONSTEXPR_CHECK(hana::equal(
                hana::eval_if(logical(false), t, e),
                comparable(1)
            ));
        }

        // while_
        {
            auto smaller_than = [](auto n) {
                return [n](auto v) { return v.size() < n; };
            };
            auto f = [](auto v) {
                v.push_back(v.size());
                return v;
            };

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(0u), std::vector<int>{}, f),
                std::vector<int>{}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(1u), std::vector<int>{}, f),
                std::vector<int>{0}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(2u), std::vector<int>{}, f),
                std::vector<int>{0, 1}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(3u), std::vector<int>{}, f),
                std::vector<int>{0, 1, 2}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(4u), std::vector<int>{}, f),
                std::vector<int>{0, 1, 2, 3}
            ));

            // Make sure it can be called with an lvalue state:
            std::vector<int> v{};
            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(smaller_than(4u), v, f),
                std::vector<int>{0, 1, 2, 3}
            ));
        }

        // while_
        {
            auto less_than = [](auto n) {
                return [n](auto v) { return v.size() < n; };
            };
            auto f = [](auto v) {
                v.push_back(v.size());
                return v;
            };

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(0u), std::vector<int>{}, f),
                std::vector<int>{}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(1u), std::vector<int>{}, f),
                std::vector<int>{0}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(2u), std::vector<int>{}, f),
                std::vector<int>{0, 1}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(3u), std::vector<int>{}, f),
                std::vector<int>{0, 1, 2}
            ));

            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(4u), std::vector<int>{}, f),
                std::vector<int>{0, 1, 2, 3}
            ));

            // Make sure it can be called with an lvalue state:
            std::vector<int> v{};
            BOOST_HANA_RUNTIME_CHECK(hana::equal(
                hana::while_(less_than(4u), v, f),
                std::vector<int>{0, 1, 2, 3}
            ));
        }
    }
}


// Boost.Geometry Index
// Unit Test

// Copyright (c) 2011-2013 Adam Wulkiewicz, Lodz, Poland.

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

#include <algorithm>

#include <geometry_index_test_common.hpp>

#include <boost/geometry/index/detail/algorithms/minmaxdist.hpp>

#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>

#define BOOST_GEOMETRY_TEST_DEBUG

template <typename Point, typename Indexable>
void test(Point const& pt, Indexable const& indexable,
    typename bg::default_distance_result<Point, Indexable>::type expected_value)
{
    typename bg::default_distance_result<Point, Indexable>::type value = bgi::detail::minmaxdist(pt, indexable);

#ifdef BOOST_GEOMETRY_TEST_DEBUG
    std::ostringstream out;
    out << typeid(typename bg::coordinate_type<Point>::type).name()
        << " "
        << typeid(typename bg::coordinate_type<Indexable>::type).name()
        << " "
        << typeid(bg::default_distance_result<Point, Indexable>::type).name()
        << " "
        << "minmaxdist : " << value
        << std::endl;
    std::cout << out.str();
#endif

    BOOST_CHECK_CLOSE(value, expected_value, 0.0001);
}

template <typename Indexable, typename Point>
void test_indexable(Point const& pt, std::string const& wkt,
    typename bg::default_distance_result<Point, Indexable>::type expected_value)
{
    Indexable indexable;
    bg::read_wkt(wkt, indexable);
    test(pt, indexable, expected_value);
}

void test_large_integers()
{
    typedef bg::model::point<int, 2, bg::cs::cartesian> int_point_type;
    typedef bg::model::point<double, 2, bg::cs::cartesian> double_point_type;

    int_point_type int_pt(0, 0);
    double_point_type double_pt(0, 0);

    bg::model::box<int_point_type> int_box;
    bg::model::box<double_point_type> double_box;

    std::string const box_li = "POLYGON((1536119 192000, 1872000 528000))";
    bg::read_wkt(box_li, int_box);
    bg::read_wkt(box_li, double_box);

    BOOST_CHECK(bgi::detail::minmaxdist(int_pt, int_box) == bgi::detail::minmaxdist(double_pt, double_box));
}

int test_main(int, char* [])
{
    typedef bg::model::point<int, 2, bg::cs::cartesian> P2ic;
    typedef bg::model::point<float, 2, bg::cs::cartesian> P2fc;
    typedef bg::model::point<double, 2, bg::cs::cartesian> P2dc;

    typedef bg::model::point<int, 3, bg::cs::cartesian> P3ic;
    typedef bg::model::point<float, 3, bg::cs::cartesian> P3fc;
    typedef bg::model::point<double, 3, bg::cs::cartesian> P3dc;

    test_indexable<bg::model::box<P2ic> >(P2ic(1, 2), "POLYGON((0 1,2 4))", 5.0);
    test_indexable<bg::model::box<P2fc> >(P2fc(1, 2), "POLYGON((0 1,2 4))", 5.0);
    test_indexable<bg::model::box<P2dc> >(P2dc(1, 2), "POLYGON((0 1,2 4))", 5.0);
    test_indexable<bg::model::box<P3ic> >(P3ic(1, 2, 3), "POLYGON((0 1 2,2 4 6))", 14.0);
    test_indexable<bg::model::box<P3fc> >(P3fc(1, 2, 3), "POLYGON((0 1 2,2 4 6))", 14.0);
    test_indexable<bg::model::box<P3dc> >(P3dc(1, 2, 3), "POLYGON((0 1 2,2 4 6))", 14.0);

    test_indexable<bg::model::box<P2ic> >(P2ic(1, 2), "POLYGON((1 2,3 5))", 4.0);

#ifdef HAVE_TTMATH
    typedef bg::model::point<ttmath_big, 2, bg::cs::cartesian> P2ttmc;
    typedef bg::model::point<ttmath_big, 3, bg::cs::cartesian> P3ttmc;

    test_indexable<bg::model::box<P2ttmc> >(P2ttmc(1, 2), "POLYGON((0 1,2 4))", 5.0);
    test_indexable<bg::model::box<P3ttmc> >(P3ttmc(1, 2, 3), "POLYGON((0 1 2,2 4 6))", 14.0);
#endif

    test_large_integers();

    return 0;
}


// An example showing TEASER++ registration with the Stanford bunny model
#include <chrono>
#include <iostream>
#include <random>
#include <fstream>
#include <Eigen/Core>

#include <teaser/ply_io.h>
#include <teaser/registration.h>

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

  // argv[1:]: "path_to_src_cloud", "path_to_out_cloud", "float_noise_bound", "float.cbar2", "bool_estimate_scaling",
  //            "int_rotation_max_iterations", "float_rotation_gnc_factor", "float_rotation_cost_threshold",
  //            "path_to_correspondences_file"

  // Load the .ply file
  teaser::PLYReader reader;
  teaser::PointCloud src_cloud, tgt_cloud;
  auto status = reader.read(argv[1], src_cloud);
  status = reader.read(argv[2], tgt_cloud);
  std::vector<std::pair<int, int>> correspondences;
  std::ifstream corr_file(argv[9]);

  int x, y;
  while(corr_file >> x >> y)
  {
      correspondences.push_back(std::make_pair(x, y));
  }

  int N_src = src_cloud.size();
  int N_tgt = tgt_cloud.size();

  // Convert the point clouds to Eigen
  Eigen::Matrix<double, 3, Eigen::Dynamic> src(3, N_src);
  for (size_t i = 0; i < N_src; ++i) {
    src.col(i) << src_cloud[i].x, src_cloud[i].y, src_cloud[i].z;
  }
  Eigen::Matrix<double, 3, Eigen::Dynamic> tgt(3, N_tgt);
  for (size_t i = 0; i < N_tgt; ++i) {
    tgt.col(i) << tgt_cloud[i].x, tgt_cloud[i].y, tgt_cloud[i].z;
  }

  // Run TEASER++ registration
  // Prepare solver parameters
  teaser::RobustRegistrationSolver::Params params;
  params.noise_bound = std::stof(argv[3]);
  params.cbar2 = std::stof(argv[4]);
  params.estimate_scaling = std::stoi(argv[5]);
  params.rotation_max_iterations = std::stoi(argv[6]);
  params.rotation_gnc_factor = std::stof(argv[7]);
  params.rotation_estimation_algorithm =
      teaser::RobustRegistrationSolver::ROTATION_ESTIMATION_ALGORITHM::GNC_TLS;
  params.rotation_cost_threshold = std::stof(argv[8]);

  // Solve with TEASER++
  teaser::RobustRegistrationSolver solver(params);
  std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
  solver.solve(src_cloud, tgt_cloud, correspondences);
  std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

  auto solution = solver.getSolution();

  // Compare results
  std::cout << "=====================================" << std::endl;
  std::cout << "          TEASER++ Results           " << std::endl;
  std::cout << "=====================================" << std::endl;
    std::cout << "Estimated rotation: " << std::endl;
  std::cout << solution.rotation << std::endl;
  std::cout << "Estimated translation: " << std::endl;
  std::cout << solution.translation << std::endl;
  std::cout << "Estimated scale: " << std::endl;
  std::cout << solution.scale << std::endl;
  std::cout << std::endl;

  std::cout << "Time taken (s): "
            << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() /
                   1000000.0
            << std::endl;
}


#include "DarkART/Wavefunctions_Initial.hpp"

#include <cmath>
#include <complex>
#include <fstream>
#include <stdlib.h>

#include <boost/math/quadrature/gauss_kronrod.hpp>

#include "libphysica/Integration.hpp"
#include "libphysica/Natural_Units.hpp"
#include "libphysica/Utilities.hpp"

#include "DarkART/Special_Functions.hpp"
#include "DarkART/version.hpp"

namespace DarkART
{
using namespace std::complex_literals;
using namespace libphysica::natural_units;
using namespace boost::math::quadrature;
using boost::math::factorial;

double a0 = Bohr_Radius;
double au = 27.211386245988 * eV;

// 1. Initial state: Roothaan-Hartree-Fock Ground-State Atomic Wave Functions

void Initial_Electron_State::Import_RHF_Coefficients()
{
	std::string filepath = TOP_LEVEL_DIR "data/" + Orbital_Name() + ".txt";
	if(libphysica::File_Exists(filepath) == false)
	{
		std::cerr << "Error in Initial_Electron_State::Import_RHF_Coefficients(): Coefficient table for " << Orbital_Name() << " does not exist." << std::endl;
		std::exit(EXIT_FAILURE);
	}

	std::ifstream f;
	f.open(filepath);
	if(f.is_open())
	{
		f >> binding_energy;
		binding_energy *= au;
		double C, Z;
		unsigned int nin;
		while(f >> nin >> Z >> C)
		{
			n_lj.push_back(nin);
			Z_lj.push_back(Z);
			C_nlj.push_back(C);
		}
		f.close();
	}
	Z_eff = sqrt(-2.0 * binding_energy / au) * n;
}

void Initial_Electron_State::Check_Normalization()
{
	double norm = Normalization();
	if(std::fabs(1.0 - norm) > 1.0e-4)
	{
		std::cout << "Error in Initial_Electron_State(): Normalization of " << element_name << " = " << norm << " != 1.0" << std::endl;
		std::exit(EXIT_FAILURE);
	}
}

Initial_Electron_State::Initial_Electron_State()
: element_name("none"), n(0), l(0), binding_energy(0.0), Z_eff(0.0)
{
}

Initial_Electron_State::Initial_Electron_State(const std::string& element, int N, int L)
: element_name(element), n(N), l(L)
{
	Import_RHF_Coefficients();
	Check_Normalization();
}

Initial_Electron_State::Initial_Electron_State(const std::string& element, std::string shell_name)
: element_name(element)
{
	n = shell_name[0] - '0';
	for(l = 0; l < l_orbital_names.size(); l++)
		if(shell_name[1] == l_orbital_names[l][0])
			break;
	Import_RHF_Coefficients();
	Check_Normalization();
}

std::string Initial_Electron_State::Orbital_Name() const
{
	return element_name + "_" + std::to_string(n) + l_orbital_names[l];
}

double Initial_Electron_State::Radial_Wavefunction(double r) const
{
	double R_nl = 0.0;
	for(unsigned int j = 0; j < C_nlj.size(); j++)
		R_nl += C_nlj[j] * std::pow(2.0 * Z_lj[j], n_lj[j] + 0.5) / sqrt(factorial<double>(2.0 * n_lj[j])) * std::pow(r / a0, n_lj[j] - 1.0) * std::exp(-Z_lj[j] * r / a0);

	return std::pow(a0, -1.5) * R_nl;
}

double Initial_Electron_State::Radial_Wavefunction_Derivative(double r) const
{
	double dR_dr = 0.0;
	for(unsigned int j = 0; j < C_nlj.size(); j++)
		dR_dr += C_nlj[j] * std::pow(2.0 * Z_lj[j], n_lj[j] + 0.5) / sqrt(factorial<double>(2.0 * n_lj[j])) * ((n_lj[j] - 1.0) / a0 * std::pow(r / a0, n_lj[j] - 2.0) - Z_lj[j] / a0 * std::pow(r / a0, n_lj[j] - 1.0)) * std::exp(-Z_lj[j] * r / a0);

	return std::pow(a0, -1.5) * dR_dr;
}

double Initial_Electron_State::Normalization() const
{
	std::function<double(double)> integrand = [this](double r) {
		double R = Radial_Wavefunction(r);
		return r * r * R * R;
	};
	// Integrate with Gauss Legendre
	return libphysica::Integrate_Gauss_Legendre(integrand, 0.0, 50.0 * Bohr_Radius, 1000);
}

double Initial_Electron_State::Radial_Integral(double r) const
{
	std::function<double(double)> integrand = [this](double rprime) {
		double R = Radial_Wavefunction(rprime);
		return rprime * rprime * R * R;
	};
	return gauss_kronrod<double, 31>::integrate(integrand, 0.0, r, 5, 1e-9);
}

void Initial_Electron_State::Print_Summary(unsigned int mpi_rank) const
{
	if(mpi_rank == 0)
	{
		std::cout << SEPARATOR
				  << Orbital_Name() << " - Summary" << std::endl
				  << std::endl
				  << "Binding energy [eV]:\t" << In_Units(binding_energy, eV) << std::endl
				  << "Z_effective:\t\t" << Z_eff << std::endl
				  << std::endl
				  << "n_lj\tZ_lj\tC_nlj" << std::endl;
		for(unsigned int i = 0; i < C_nlj.size(); i++)
			std::cout << n_lj[i] << "\t" << Z_lj[i] << "\t" << C_nlj[i] << std::endl;
	}
}

}	// namespace DarkART


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

#include <iostream>

namespace bmath = boost::math;

inline double normal_cdf(const double x, const double mean, const double sd) {
    if (sd == 0.0) {return 0.0;}
    return bmath::cdf(bmath::normal(mean, sd), x);
}

inline double normal_ccdf(const double x, const double mean, const double sd) {
    if (sd == 0.0) {return 0.0;}
    return bmath::cdf(bmath::complement(bmath::normal(mean, sd), x));
}

int main() {
    std::cout << normal_cdf(0.0, 0.0, 1.0) << std::endl;
    std::cout << normal_cdf(0.0, 0.0, 1.0) << std::endl;
    return 0;
}